Merge pull request #303 from Microsoft/ls

Enable basic Language Service on the new compiler
This commit is contained in:
Mohamed Hegazy
2014-07-31 19:10:06 -07:00
513 changed files with 47069 additions and 673 deletions
+5 -7
View File
@@ -62,19 +62,17 @@ var servicesSources = [
var harnessSources = [
"harness.ts",
"sourceMapRecorder.ts",
// TODO Re-enable
// "harnessLanguageService.ts",
// "fourslash.ts",
"runner.ts",
"harnessLanguageService.ts",
"fourslash.ts",
"external/json2.ts",
"runnerbase.ts",
"compilerRunner.ts",
"typeWriter.ts",
// TODO Re-enable fourslash and project tests
// "fourslashRunner.ts",
"fourslashRunner.ts",
"projectsRunner.ts",
"unittestrunner.ts",
"rwcRunner.ts",
"runner.ts"
].map(function (f) {
return path.join(harnessDirectory, f);
});
@@ -233,7 +231,7 @@ task("generate-diagnostics", [diagnosticInfoMapTs])
var tcFile = path.join(builtLocalDirectory, "tc.js");
compileFile(tcFile, compilerSources, [builtLocalDirectory, copyright].concat(compilerSources), [copyright], /*useBuiltCompiler:*/ false);
var tcServicesFile = path.join(builtLocalDirectory, "services.js");
var tcServicesFile = path.join(builtLocalDirectory, "typescriptServices.js");
compileFile(tcServicesFile, servicesSources, [builtLocalDirectory, copyright].concat(servicesSources), [copyright], /*useBuiltCompiler:*/ true);
// Local target to build the compiler and services
+94 -46
View File
@@ -63,7 +63,32 @@ module ts {
var diagnostics: Diagnostic[] = [];
var diagnosticsModified: boolean = false;
var checker: TypeChecker;
var checker: TypeChecker = {
getProgram: () => program,
getDiagnostics: getDiagnostics,
getGlobalDiagnostics: getGlobalDiagnostics,
getNodeCount: () => sum(program.getSourceFiles(), "nodeCount"),
getIdentifierCount: () => sum(program.getSourceFiles(), "identifierCount"),
getSymbolCount: () => sum(program.getSourceFiles(), "symbolCount"),
getTypeCount: () => typeCount,
checkProgram: checkProgram,
emitFiles: invokeEmitter,
getSymbolOfNode: getSymbolOfNode,
getParentOfSymbol: getParentOfSymbol,
getTypeOfSymbol: getTypeOfSymbol,
getDeclaredTypeOfSymbol: getDeclaredTypeOfSymbol,
getPropertiesOfType: getPropertiesOfType,
getSignaturesOfType: getSignaturesOfType,
getIndexTypeOfType: getIndexTypeOfType,
getReturnTypeOfSignature: getReturnTypeOfSignature,
resolveEntityName: resolveEntityName,
getSymbolsInScope: getSymbolsInScope,
getSymbolOfIdentifier: getSymbolOfIdentifier,
getTypeOfExpression: getTypeOfExpression,
typeToString: typeToString,
symbolToString: symbolToString,
getAugmentedPropertiesOfApparentType: getAugmentedPropertiesOfApparentType
};
function addDiagnostic(diagnostic: Diagnostic) {
diagnostics.push(diagnostic);
@@ -739,10 +764,10 @@ module ts {
};
}
function typeToString(type: Type, flags?: TypeFormatFlags): string {
function typeToString(type: Type, enclosingDeclaration?:Node, flags?: TypeFormatFlags): string {
var stringWriter = createSingleLineTextWriter();
// TODO(shkamat): typeToString should take enclosingDeclaration as input, once we have implemented enclosingDeclaration
writeTypeToTextWriter(type, /*enclosingDeclaration*/ null, flags, stringWriter);
writeTypeToTextWriter(type, enclosingDeclaration, flags, stringWriter);
return stringWriter.getText();
}
@@ -1379,7 +1404,7 @@ module ts {
type.baseTypes.push(baseType);
}
else {
error(declaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, TypeFormatFlags.WriteArrayAsGenericType));
error(declaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType));
}
}
else {
@@ -1420,7 +1445,7 @@ module ts {
type.baseTypes.push(baseType);
}
else {
error(declaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, TypeFormatFlags.WriteArrayAsGenericType));
error(declaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType));
}
}
else {
@@ -1987,7 +2012,7 @@ module ts {
type = createTypeReference(<GenericType>type, map(node.typeArguments, t => getTypeFromTypeNode(t)));
}
else {
error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, typeToString(type, TypeFormatFlags.WriteArrayAsGenericType), typeParameters.length);
error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType), typeParameters.length);
type = undefined;
}
}
@@ -2387,7 +2412,7 @@ module ts {
var errorInfo = chainDiagnosticMessages(undefined, Diagnostics.Named_properties_0_of_types_1_and_2_are_not_identical, prop.name, typeName1, typeName2);
errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Interface_0_cannot_simultaneously_extend_types_1_and_2_Colon, typeToString(type), typeName1, typeName2);
addDiagnostic(createDiagnosticForNodeFromMessageChain(typeNode, errorInfo));
addDiagnostic(createDiagnosticForNodeFromMessageChain(typeNode, errorInfo, program.getCompilerHost().getNewLine()));
}
}
}
@@ -2434,7 +2459,7 @@ module ts {
error(errorNode, Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, typeToString(source), typeToString(target));
}
else if (errorInfo) {
addDiagnostic(createDiagnosticForNodeFromMessageChain(errorNode, errorInfo));
addDiagnostic(createDiagnosticForNodeFromMessageChain(errorNode, errorInfo, program.getCompilerHost().getNewLine()));
}
return result;
@@ -4784,14 +4809,6 @@ module ts {
return (node.flags & NodeFlags.Private) && isInAmbientContext(node);
}
function isInAmbientContext(node: Node): boolean {
while (node) {
if (node.flags & (NodeFlags.Ambient | NodeFlags.DeclarationFile)) return true;
node = node.parent;
}
return false;
}
function checkSpecializedSignatureDeclaration(signatureDeclarationNode: SignatureDeclaration): void {
var signature = getSignatureFromDeclaration(signatureDeclarationNode);
if (!signature.hasStringLiterals) {
@@ -6181,7 +6198,7 @@ module ts {
// True if the given identifier is part of a type reference
function isTypeReferenceIdentifier(identifier: Identifier): boolean {
var node: Node = identifier;
while (node.parent && node.parent.kind === SyntaxKind.QualifiedName) node = node.parent;
if (node.parent && node.parent.kind === SyntaxKind.QualifiedName) node = node.parent;
return node.parent && node.parent.kind === SyntaxKind.TypeReference;
}
@@ -6245,10 +6262,20 @@ module ts {
return false;
}
function isRightSideOfQualifiedName(node: Node) {
return (node.parent.kind === SyntaxKind.QualifiedName || node.parent.kind === SyntaxKind.PropertyAccess) &&
(<QualifiedName>node.parent).right === node;
}
function getSymbolOfIdentifier(identifier: Identifier) {
if (isExpression(identifier)) {
if (isRightSideOfQualifiedName()) {
// TODO
if (isRightSideOfQualifiedName(identifier)) {
var node = <QualifiedName>identifier.parent;
var symbol = getNodeLinks(node).resolvedSymbol;
if (!symbol) {
checkPropertyAccess(node);
}
return getNodeLinks(node).resolvedSymbol;
}
return resolveEntityName(identifier, identifier, SymbolFlags.Value);
}
@@ -6256,16 +6283,58 @@ module ts {
return getSymbolOfNode(identifier.parent);
}
if (isTypeReferenceIdentifier(identifier)) {
var entityName = isRightSideOfQualifiedName() ? identifier.parent : identifier;
var entityName = isRightSideOfQualifiedName(identifier) ? identifier.parent : identifier;
var meaning = entityName.parent.kind === SyntaxKind.TypeReference ? SymbolFlags.Type : SymbolFlags.Namespace;
return resolveEntityName(entityName, entityName, meaning);
}
function isRightSideOfQualifiedName() {
return (identifier.parent.kind === SyntaxKind.QualifiedName || identifier.parent.kind === SyntaxKind.PropertyAccess) &&
(<QualifiedName>identifier.parent).right === identifier;
}
}
function getTypeOfExpression(node: Node) {
if (isExpression(node)) {
while (isRightSideOfQualifiedName(node)) {
node = node.parent;
}
return <Type>getApparentType(checkExpression(node));
}
return unknownType;
}
function getAugmentedPropertiesOfApparentType(type: Type): Symbol[]{
var apparentType = getApparentType(type);
if (apparentType.flags & TypeFlags.ObjectType) {
// Augment the apprent type with Function and Object memeber as applicaple
var propertiesByName: Map<Symbol> = {};
var results: Symbol[] = [];
forEach(getPropertiesOfType(apparentType), (s) => {
propertiesByName[s.name] = s;
results.push(s);
});
var resolved = resolveObjectTypeMembers(<ObjectType>type);
forEachValue(resolved.members, (s) => {
if (symbolIsValue(s) && !propertiesByName[s.name]) {
propertiesByName[s.name] = s;
results.push(s);
}
});
if (resolved === anyFunctionType || resolved.callSignatures.length || resolved.constructSignatures.length) {
forEach(getPropertiesOfType(globalFunctionType), (s) => {
if (!propertiesByName[s.name]) {
propertiesByName[s.name] = s;
results.push(s);
}
});
}
return results;
}
else {
return getPropertiesOfType(<Type>apparentType);
}
}
// Emitter support
function isExternalModuleSymbol(symbol: Symbol): boolean {
@@ -6459,28 +6528,7 @@ module ts {
}
initializeTypeChecker();
checker = {
getProgram: () => program,
getDiagnostics: getDiagnostics,
getGlobalDiagnostics: getGlobalDiagnostics,
getNodeCount: () => sum(program.getSourceFiles(), "nodeCount"),
getIdentifierCount: () => sum(program.getSourceFiles(), "identifierCount"),
getSymbolCount: () => sum(program.getSourceFiles(), "symbolCount"),
getTypeCount: () => typeCount,
checkProgram: checkProgram,
emitFiles: invokeEmitter,
getSymbolOfNode: getSymbolOfNode,
getParentOfSymbol: getParentOfSymbol,
getTypeOfSymbol: getTypeOfSymbol,
getDeclaredTypeOfSymbol: getDeclaredTypeOfSymbol,
getPropertiesOfType: getPropertiesOfType,
getSignaturesOfType: getSignaturesOfType,
getIndexTypeOfType: getIndexTypeOfType,
getReturnTypeOfSignature: getReturnTypeOfSignature,
resolveEntityName: resolveEntityName,
getSymbolsInScope: getSymbolsInScope,
getSymbolOfIdentifier: getSymbolOfIdentifier
};
return checker;
}
}
+14 -2
View File
@@ -134,6 +134,18 @@ module ts {
return result;
}
export function forEachKey<T, U>(map: Map<T>, callback: (key: string) => U): U {
var result: U;
for (var id in map) {
if (result = callback(id)) break;
}
return result;
}
export function lookUp<T>(map: Map<T>, key: string): T {
return hasProperty(map, key) ? map[key] : undefined;
}
export function mapToArray<T>(map: Map<T>): T[] {
var result: T[] = [];
for (var id in map) result.push(map[id]);
@@ -214,7 +226,7 @@ module ts {
}
}
export function flattenDiagnosticChain(file: SourceFile, start: number, length: number, diagnosticChain: DiagnosticMessageChain): Diagnostic {
export function flattenDiagnosticChain(file: SourceFile, start: number, length: number, diagnosticChain: DiagnosticMessageChain, newLine: string): Diagnostic {
var code = diagnosticChain.code;
var category = diagnosticChain.category;
var messageText = "";
@@ -222,7 +234,7 @@ module ts {
var indent = 0;
while (diagnosticChain) {
if (indent) {
messageText += sys.newLine;
messageText += newLine;
for (var i = 0; i < indent; i++) {
messageText += " ";
+3 -2
View File
@@ -22,6 +22,7 @@ module ts {
var compilerOptions = program.getCompilerOptions();
var sourceMapDataList: SourceMapData[] = compilerOptions.sourceMap ? [] : undefined;
var diagnostics: Diagnostic[] = [];
var newLine = program.getCompilerHost().getNewLine();
function getSourceFilePathInNewDir(newDirPath: string, sourceFile: SourceFile) {
var sourceFilePath = getNormalizedPathFromPathCompoments(getNormalizedPathComponents(sourceFile.filename, compilerHost.getCurrentDirectory()));
@@ -126,7 +127,7 @@ module ts {
function writeLine() {
if (!lineStart) {
output += sys.newLine;
output += newLine;
lineCount++;
linePos = output.length;
lineStart = true;
@@ -2252,7 +2253,7 @@ module ts {
compilerHost.getCurrentDirectory(),
/*isAbsolutePathAnUrl*/ false);
referencePathsOutput += "/// <reference path='" + declFileName + "' />" + sys.newLine;
referencePathsOutput += "/// <reference path='" + declFileName + "' />" + newLine;
}
if (root) {
+16 -3
View File
@@ -88,12 +88,12 @@ module ts {
return createFileDiagnostic(file, start, length, message, arg0, arg1, arg2);
}
export function createDiagnosticForNodeFromMessageChain(node: Node, messageChain: DiagnosticMessageChain): Diagnostic {
export function createDiagnosticForNodeFromMessageChain(node: Node, messageChain: DiagnosticMessageChain, newLine: string): Diagnostic {
node = getErrorSpanForNode(node);
var file = getSourceFileOfNode(node);
var start = skipTrivia(file.text, node.pos);
var length = node.end - start;
return flattenDiagnosticChain(file, start, length, messageChain);
return flattenDiagnosticChain(file, start, length, messageChain, newLine);
}
export function getErrorSpanForNode(node: Node): Node {
@@ -327,6 +327,14 @@ module ts {
return s.parameters.length > 0 && (s.parameters[s.parameters.length - 1].flags & NodeFlags.Rest) !== 0;
}
export function isInAmbientContext(node: Node): boolean {
while (node) {
if (node.flags & (NodeFlags.Ambient | NodeFlags.DeclarationFile)) return true;
node = node.parent;
}
return false;
}
enum ParsingContext {
SourceElements, // Elements in source file
ModuleElements, // Elements in module declaration
@@ -1624,7 +1632,12 @@ module ts {
parameter.name = identifier;
finishNode(parameter);
var signature = <ParsedSignature> { parameters: [parameter] };
var parameters = <NodeArray<ParameterDeclaration>>[];
parameters.push(parameter);
parameters.pos = parameter.pos;
parameters.end = parameter.end;
var signature = <ParsedSignature> { parameters: parameters };
return parseArrowExpressionTail(identifier.pos, signature, /*noIn:*/ false);
}
+2 -1
View File
@@ -174,7 +174,8 @@ module ts {
writeFile: writeFile,
getCurrentDirectory: () => currentDirectory || (currentDirectory = sys.getCurrentDirectory()),
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
getCanonicalFileName: getCanonicalFileName
getCanonicalFileName: getCanonicalFileName,
getNewLine: () => sys.newLine
};
}
+12
View File
@@ -599,6 +599,10 @@ module ts {
resolveEntityName(location: Node, name: EntityName, meaning: SymbolFlags): Symbol;
getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[];
getSymbolOfIdentifier(identifier: Identifier): Symbol;
getTypeOfExpression(node: Expression, contextualType?: Type, contextualMapper?: TypeMapper): Type;
typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string;
symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string;
getAugmentedPropertiesOfApparentType(type: Type): Symbol[];
}
export interface TextWriter {
@@ -1104,5 +1108,13 @@ module ts {
getCurrentDirectory(): string;
getCanonicalFileName(fileName: string): string;
useCaseSensitiveFileNames(): boolean;
getNewLine(): string;
}
export enum ByteOrderMark {
None = 0,
Utf8 = 1,
Utf16BigEndian = 2,
Utf16LittleEndian = 3,
}
}
+209 -255
View File
@@ -14,6 +14,7 @@
//
/// <reference path='..\services\services.ts' />
/// <reference path='harnessLanguageService.ts' />
/// <reference path='harness.ts' />
module FourSlash {
@@ -108,7 +109,7 @@ module FourSlash {
High
}
var entityMap: TypeScript.IIndexable<string> = {
var entityMap: ts.Map<string> = {
'&': '&amp;',
'"': '&quot;',
"'": '&#39;',
@@ -127,7 +128,7 @@ module FourSlash {
export var currentTestState: TestState = null;
export class TestCancellationToken implements TypeScript.ICancellationToken {
export class TestCancellationToken implements ts.CancellationToken {
// 0 - cancelled
// >0 - not cancelled
// <0 - not cancelled and value denotes number of isCancellationRequested after which token become cancelled
@@ -162,7 +163,7 @@ module FourSlash {
f();
}
catch (e) {
if (e instanceof TypeScript.OperationCanceledException) {
if (e instanceof ts.OperationCanceledException) {
return;
}
}
@@ -172,9 +173,8 @@ module FourSlash {
export class TestState {
// Language service instance
public languageServiceShimHost: Harness.TypeScriptLS = null;
private languageService: TypeScript.Services.ILanguageService = null;
private newLanguageService: ts.LanguageService = null;
public languageServiceShimHost: Harness.LanguageService.TypeScriptLS;
private languageService: ts.LanguageService;
// A reference to the language service's compiler state's compiler instance
private compiler: () => { getSyntaxTree(fileName: string): TypeScript.SyntaxTree; getSourceUnit(fileName: string): TypeScript.SourceUnitSyntax; };
@@ -189,7 +189,7 @@ module FourSlash {
// Whether or not we should format on keystrokes
public enableFormatting = true;
public formatCodeOptions: TypeScript.Services.FormatCodeOptions = null;
public formatCodeOptions: ts.FormatCodeOptions;
public cancellationToken: TestCancellationToken;
@@ -202,7 +202,7 @@ module FourSlash {
constructor(public testData: FourSlashData) {
// Initialize the language service with all the scripts
this.cancellationToken = new TestCancellationToken();
this.languageServiceShimHost = new Harness.TypeScriptLS(this.cancellationToken);
this.languageServiceShimHost = new Harness.LanguageService.TypeScriptLS(this.cancellationToken);
var harnessCompiler = Harness.Compiler.getCompiler();
var inputFiles: { unitName: string; content: string }[] = [];
@@ -226,40 +226,48 @@ module FourSlash {
});
}
// NEWTODO: Re-implement commented-out section
// harnessCompiler.addInputFiles(inputFiles);
try {
// var resolvedFiles = harnessCompiler.resolve();
// NEWTODO: Re-implement commented-out section
//harnessCompiler.addInputFiles(inputFiles);
//try {
// var resolvedFiles = harnessCompiler.resolve();
//resolvedFiles.forEach(file => {
// if (!Harness.isLibraryFile(file.path)) {
// var fixedPath = file.path.substr(file.path.indexOf('tests/'));
// var content = harnessCompiler.getContentForFile(fixedPath);
// this.languageServiceShimHost.addScript(fixedPath, content);
// }
//});
// resolvedFiles.forEach(file => {
// if (!Harness.isLibraryFile(file.path)) {
// var fixedPath = file.path.substr(file.path.indexOf('tests/'));
// var content = harnessCompiler.getContentForFile(fixedPath);
// this.languageServiceShimHost.addScript(fixedPath, content);
// }
// });
// NEWTODO: For now do not resolve, just use the input files
inputFiles.forEach(file => {
if (!Harness.isLibraryFile(file.unitName)) {
this.languageServiceShimHost.addScript(file.unitName, file.content);
}
});
// this.languageServiceShimHost.addScript('lib.d.ts', Harness.Compiler.libTextMinimal);
//}
//finally {
// // harness no longer needs the results of the above work, make sure the next test operations are in a clean state
// harnessCompiler.reset();
//}
this.languageServiceShimHost.addScript('lib.d.ts', Harness.Compiler.libTextMinimal);
}
finally {
// harness no longer needs the results of the above work, make sure the next test operations are in a clean state
//harnessCompiler.reset();
}
/// NEWTODO: For now do not resolve, just use the input files
inputFiles.forEach(file => {
if (!Harness.isLibraryFile(file.unitName)) {
this.languageServiceShimHost.addScript(file.unitName, file.content);
this.newLanguageService = this.languageServiceShimHost.newLS;
}
});
this.formatCodeOptions = new TypeScript.Services.FormatCodeOptions();
this.languageServiceShimHost.addScript('lib.d.ts', Harness.Compiler.libTextMinimal);
// Sneak into the language service and get its compiler so we can examine the syntax trees
this.languageService = this.languageServiceShimHost.getLanguageService().languageService;
var compilerState = (<any>this.languageService).compiler;
this.compiler = () => compilerState.compiler;
this.formatCodeOptions = {
IndentSize: 4,
TabSize: 4,
NewLineCharacter: sys.newLine,
ConvertTabsToSpaces: true,
InsertSpaceAfterCommaDelimiter: true,
InsertSpaceAfterSemicolonInForStatements: true,
InsertSpaceBeforeAndAfterBinaryOperators: true,
InsertSpaceAfterKeywordsInControlFlowStatements: true,
@@ -308,7 +316,7 @@ module FourSlash {
this.scenarioActions.push('<MoveCaretRight NumberOfChars="' + count + '" />');
} else {
this.scenarioActions.push('<MoveCaretLeft NumberOfChars="' + (-count) + '" />');
fileToOpen.fileName = Harness.Path.switchToForwardSlashes(fileToOpen.fileName);
}
}
// Opens a file given its 0-based index or fileName
@@ -318,9 +326,7 @@ module FourSlash {
var fileToOpen: FourSlashFile = this.findFile(indexOrName);
fileToOpen.fileName = ts.normalizeSlashes(fileToOpen.fileName);
this.activeFile = fileToOpen;
// NEWTODO: make this more specific again
//return ((errorMinChar === startPos) && (errorLimChar === endPos)) ? true : false;
return ((errorMinChar >= startPos) && (errorLimChar <= endPos)) ? true : false;
var filename = fileToOpen.fileName.replace(Harness.IO.directoryName(fileToOpen.fileName), '').substr(1);
this.scenarioActions.push('<OpenFile FileName="" SrcFileId="' + filename + '" FileId="' + filename + '" />');
}
@@ -328,28 +334,15 @@ module FourSlash {
var startMarker = this.getMarkerByName(startMarkerName);
var endMarker = this.getMarkerByName(endMarkerName);
var predicate = function (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) {
this.new_printErrorLog(negative, this.new_getAllDiagnostics());
return ((errorMinChar === startPos) && (errorLimChar === endPos)) ? true : false;
};
var exists = this.anyErrorInRange(predicate, startMarker, endMarker);
private getDiagnostics(fileName: string): TypeScript.Diagnostic[] {
this.taoInvalidReason = 'verifyErrorExistsBetweenMarkers NYI';
if (exists !== negative) {
this.printErrorLog(negative, this.getAllDiagnostics());
var diagnostics: TypeScript.Diagnostic[] = [];
diagnostics.push.apply(diagnostics, syntacticErrors);
diagnostics.push.apply(diagnostics, semanticErrors);
return diagnostics;
}
private new_getDiagnostics(fileName: string): ts.Diagnostic[] {
var syntacticErrors = this.newLanguageService.getSyntacticDiagnostics(fileName);
var semanticErrors = this.newLanguageService.getSemanticDiagnostics(fileName);
throw new Error("Failure between markers: " + startMarkerName + ", " + endMarkerName);
}
}
@@ -357,9 +350,8 @@ module FourSlash {
private getDiagnostics(fileName: string): ts.Diagnostic[] {
var syntacticErrors = this.languageService.getSyntacticDiagnostics(fileName);
var semanticErrors = this.languageService.getSemanticDiagnostics(fileName);
private getAllDiagnostics(): TypeScript.Diagnostic[] {
var diagnostics: TypeScript.Diagnostic[] = [];
var diagnostics: ts.Diagnostic[] = [];
diagnostics.push.apply(diagnostics, syntacticErrors);
diagnostics.push.apply(diagnostics, semanticErrors);
@@ -369,17 +361,6 @@ module FourSlash {
private getAllDiagnostics(): ts.Diagnostic[] {
var diagnostics: ts.Diagnostic[] = [];
private new_getAllDiagnostics(): ts.Diagnostic[] {
var diagnostics: ts.Diagnostic[] = [];
var fileNames = JSON.parse(this.languageServiceShimHost.getScriptFileNames());
for (var i = 0, n = fileNames.length; i < n; i++) {
diagnostics.push.apply(this.new_getDiagnostics(fileNames[i]));
}
return diagnostics;
}
var fileNames = JSON.parse(this.languageServiceShimHost.getScriptFileNames());
for (var i = 0, n = fileNames.length; i < n; i++) {
diagnostics.push.apply(this.getDiagnostics(fileNames[i]));
@@ -397,17 +378,17 @@ module FourSlash {
return ((errorMinChar >= startPos) && (errorLimChar >= startPos)) ? true : false;
};
} else {
var diagnostics = this.new_getAllDiagnostics();
predicate = function (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) {
return ((errorMinChar <= startPos) && (errorLimChar <= startPos)) ? true : false;
};
this.new_printErrorLog(negative, diagnostics);
}
this.taoInvalidReason = 'verifyErrorExistsAfterMarker NYI';
var exists = this.anyErrorInRange(predicate, marker);
var diagnostics = this.getAllDiagnostics();
var errors = this.new_getDiagnostics(startMarker.fileName);
if (exists !== negative) {
this.printErrorLog(negative, diagnostics);
throw new Error("Failure at marker: " + markerName);
}
@@ -415,7 +396,7 @@ module FourSlash {
private anyErrorInRange(predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => boolean, startMarker: Marker, endMarker?: Marker) {
errors.forEach((error)=> {
var errors = this.getDiagnostics(startMarker.fileName);
var exists = false;
var startPos = startMarker.position;
@@ -424,26 +405,14 @@ module FourSlash {
}
errors.forEach(function (error: ts.Diagnostic) {
private printErrorLog(expectErrors: boolean, errors: TypeScript.Diagnostic[]) {
if (predicate(error.start, error.start + error.length, startPos, endPos)) {
exists = true;
}
});
return exists;
}
errors.forEach(function (error: TypeScript.Diagnostic) {
Harness.IO.log(" minChar: " + error.start() + ", limChar: " + (error.start() + error.length()) + ", message: " + error.message() + "\n");
});
}
private new_printErrorLog(expectErrors: boolean, errors: ts.Diagnostic[]) {
if (expectErrors) {
Harness.IO.log("Expected error not found. Error list is:");
} else {
Harness.IO.log("Unexpected error(s) found. Error list is:");
}
errors.forEach(error => {
private printErrorLog(expectErrors: boolean, errors: ts.Diagnostic[]) {
if (expectErrors) {
Harness.IO.log("Expected error not found. Error list is:");
@@ -455,6 +424,7 @@ module FourSlash {
Harness.IO.log(" minChar: " + error.start + ", limChar: " + (error.start + error.length) + ", message: " + error.messageText + "\n");
});
}
public verifyNumberOfErrorsInCurrentFile(expected: number) {
var errors = this.getDiagnostics(this.activeFile.fileName);
var actual = errors.length;
@@ -754,22 +724,22 @@ module FourSlash {
else {
if (!actualQuickInfo) {
throw new Error('verifyQuickInfoExists failed. Expected quick info to exist');
assert.equal(help.prefix + help.parameters.map(p => p.display).join(help.separator) + help.suffix, expected);
}
}
}
public verifyCurrentSignatureHelpIs(expected: string) {
this.taoInvalidReason = 'verifyCurrentSignatureHelpIs NYI';
var signature = this.getActiveSignatureHelp();
assert.isNotNull(signature);
assert.equal(isVariable, signature.isVariadic);
var help = this.getActiveSignatureHelp();
assert.equal(help.signatureInfo, expected);
}
public verifyCurrentParameterIsVariable(isVariable: boolean) {
this.taoInvalidReason = 'verifyCurrentParameterIsVariable NYI';
var activeParameter = this.getActiveParameter();
var activeParameterName = activeParameter.name;
assert.isNotNull(activeParameter.parameter);
assert.equal(isVariable, activeParameter.parameter.isVariable);
}
@@ -778,14 +748,16 @@ module FourSlash {
var activeParameter = this.getActiveParameter();
var activeParameterName = activeParameter.parameter ? activeParameter.parameter.name : activeParameter.typeParameter.name;
assert.equal(activeParameter.display, parameter);
assert.equal(activeParameterName, name);
}
public verifyCurrentParameterSpanIs(parameter: string) {
this.taoInvalidReason = 'verifyCurrentParameterSpanIs NYI';
var activeSignature = this.getActiveSignatureHelp();
var activeParameter = this.getActiveParameter();
var activeParameterMinChar = activeParameter.parameter ? activeParameter.parameter.minChar : activeParameter.typeParameter.minChar;
var activeParameterDocComment = activeParameter.documentation;
var activeParameterLimChar = activeParameter.parameter ? activeParameter.parameter.limChar : activeParameter.typeParameter.limChar;
assert.equal(activeSignature.signatureInfo.substring(activeParameterMinChar, activeParameterLimChar), parameter);
}
@@ -798,13 +770,13 @@ module FourSlash {
}
public verifyCurrentSignatureHelpParameterCount(expectedCount: number) {
// assert.equal(this.getActiveSignatureHelp().typeParameters.length, expectedCount);
this.taoInvalidReason = 'verifyCurrentSignatureHelpParameterCount NYI';
assert.equal(this.getActiveSignatureHelp().parameters.length, expectedCount);
}
public verifyCurrentSignatureHelpTypeParameterCount(expectedCount: number) {
var actualDocComment = this.getActiveSignatureHelp().documentation;
this.taoInvalidReason = 'verifyCurrentSignatureHelpTypeParameterCount NYI';
assert.equal(this.getActiveSignatureHelp().typeParameters.length, expectedCount);
}
@@ -812,15 +784,15 @@ module FourSlash {
public verifyCurrentSignatureHelpDocComment(docComment: string) {
this.taoInvalidReason = 'verifyCurrentSignatureHelpDocComment NYI';
var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
var actual = help && help.items ? help.items.length : 0;
var actualDocComment = this.getActiveSignatureHelp().docComment;
assert.equal(actualDocComment, docComment);
}
public verifySignatureHelpCount(expected: number) {
this.scenarioActions.push('<InvokeSignatureHelp />');
this.scenarioActions.push('<VerifySignatureHelpOverloadCountEquals Count="' + expected + '" />');
var actual = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition);
var actual = help && help.formal ? help.formal.length : 0;
assert.equal(actual, expected);
}
@@ -832,32 +804,45 @@ module FourSlash {
if (shouldBePresent) {
if (!actual) {
throw new Error("Expected signature help to be present, but it wasn't");
//private getFormalParameter() {
// var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
// return help.formal;
//}
}
} else {
if (actual) {
throw new Error("Expected no signature help, but got '" + JSON.stringify(actual) + "'");
}
}
var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
}
private getFormalParameter() {
var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition);
return help.formal;
}
var index = help.selectedItemIndex < 0 ? 0 : help.selectedItemIndex;
private getActiveSignatureHelp() {
var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition);
var activeFormal = help.activeFormal;
return help.items[index];
// If the signature hasn't been narrowed down yet (e.g. no parameters have yet been entered),
// 'activeFormal' will be -1 (even if there is only 1 signature). Signature help will show the
private getActiveParameter(): TypeScript.Services.SignatureHelpParameter {
// first signature in the signature group, so go with that
if (activeFormal === -1) {
var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
var item = help.items[help.selectedItemIndex];
var state = this.languageService.getSignatureHelpCurrentArgumentState(this.activeFile.fileName, this.currentCaretPosition, help.applicableSpan.start());
activeFormal = 0;
}
var currentParam = state === null ? 0 : state.argumentIndex;
return item.parameters[currentParam];
return help.formal[activeFormal];
}
private getActiveParameter(): { parameter: ts.FormalParameterInfo; typeParameter: ts.FormalTypeParameterInfo; } {
var currentSig = this.getActiveSignatureHelp();
var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition);
// Same logic as in getActiveSignatureHelp - this value might be -1 until a parameter value actually gets typed
var currentParam = help.actual.currentParameter;
if (currentParam === -1) currentParam = 0;
if (help.actual.currentParameterIsTypeParameter) {
return {
parameter: null,
typeParameter: currentSig.typeParameters[currentParam]
};
}
else {
@@ -866,7 +851,7 @@ module FourSlash {
typeParameter: null
};
}
resultString = resultString + this.activeFile.content.substr(spanInfo.start(), spanInfo.length());
}
public getBreakpointStatementLocation(pos: number) {
this.taoInvalidReason = 'getBreakpointStatementLocation NYI';
@@ -884,7 +869,8 @@ module FourSlash {
Harness.Baseline.runBaseline(
"Breakpoint Locations for " + this.activeFile.fileName,
});
this.testData.globalOptions['BaselineFile'],
() => {
var fileLength = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getLength();
var resultString = "";
for (var pos = 0; pos < fileLength; pos++) {
@@ -896,7 +882,7 @@ module FourSlash {
}
public printBreakpointLocation(pos: number) {
var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition);
Harness.IO.log(this.getBreakpointStatementLocation(pos));
}
public printBreakpointAtCurrentLocation() {
@@ -906,10 +892,6 @@ module FourSlash {
public printCurrentParameterHelp() {
var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition);
Harness.IO.log(JSON.stringify(help));
Harness.IO.log("--------------");
Harness.IO.log("Old Errors");
Harness.IO.log("--------------");
}
public printCurrentQuickInfo() {
@@ -917,27 +899,7 @@ module FourSlash {
Harness.IO.log(JSON.stringify(quickInfo));
}
Harness.IO.log("start: " + err.start() + ", length: " + err.length() + ", message: " + err.message());
});
}
Harness.IO.log("--------------");
Harness.IO.log("New Errors");
Harness.IO.log("--------------");
this.new_printErrorList();
}
public new_printErrorList() {
var syntacticErrors = this.newLanguageService.getSyntacticDiagnostics(this.activeFile.fileName);
var semanticErrors = this.newLanguageService.getSemanticDiagnostics(this.activeFile.fileName);
var errorList = syntacticErrors.concat(semanticErrors);
Harness.IO.log('Error list (' + errorList.length + ' errors)');
if (errorList.length) {
errorList.forEach(error => {
Harness.IO.log("start: " + error.start + ", length: " + error.length +
", message: " + error.messageText);
public printErrorList() {
var syntacticErrors = this.languageService.getSyntacticDiagnostics(this.activeFile.fileName);
var semanticErrors = this.languageService.getSemanticDiagnostics(this.activeFile.fileName);
var errorList = syntacticErrors.concat(semanticErrors);
@@ -1100,10 +1062,10 @@ module FourSlash {
var offset = this.currentCaretPosition;
var prevChar = ' ';
for (var i = 0; i < text.length; i++) {
// Signature help
this.languageService.getSignatureHelpItems(this.activeFile.fileName, offset);
// Make the edit
var ch = text.charAt(i);
this.languageServiceShimHost.editScript(this.activeFile.fileName, offset, offset, ch);
// Completions
this.updateMarkersForEdit(this.activeFile.fileName, offset, offset, ch);
this.editCheckpoint(this.activeFile.fileName);
offset++;
@@ -1141,7 +1103,7 @@ module FourSlash {
this.scenarioActions.push('<InsertText><![CDATA[' + text + ']]></InsertText>');
var start = this.currentCaretPosition;
var edits = this.languageService.getFormattingEditsForRange(this.activeFile.fileName, start, offset, this.formatCodeOptions);
var offset = this.currentCaretPosition;
this.languageServiceShimHost.editScript(this.activeFile.fileName, offset, offset, text);
this.updateMarkersForEdit(this.activeFile.fileName, offset, offset, text);
this.editCheckpoint(this.activeFile.fileName);
@@ -1154,46 +1116,44 @@ module FourSlash {
this.editCheckpoint(this.activeFile.fileName);
}
if (this.editValidation === IncrementalEditValidation.None) {
return;
}
// Move the caret to wherever we ended up
this.currentCaretPosition = offset;
// Get syntactic errors (to force a refresh)
var incrSyntaxErrs = JSON.stringify(this.languageService.getSyntacticDiagnostics(this.activeFile.fileName));
this.fixCaretPosition();
this.checkPostEditInvariants();
}
// Check syntactic structure
var compilationSettings = new TypeScript.CompilationSettings();
compilationSettings.codeGenTarget = TypeScript.LanguageVersion.EcmaScript5;
var immutableSettings = TypeScript.ImmutableCompilationSettings.fromCompilationSettings(compilationSettings);
private checkPostEditInvariants() {
return;
var parseOptions = immutableSettings.codeGenTarget();
var snapshot = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName);
var content = snapshot.getText(0, snapshot.getLength());
var refSyntaxTree = TypeScript.Parser.parse(this.activeFile.fileName, TypeScript.SimpleText.fromString(content), parseOptions, TypeScript.isDTSFile(this.activeFile.fileName));
var fullSyntaxErrs = JSON.stringify(refSyntaxTree.diagnostics());
/// TODO: reimplement this section
//if (this.editValidation === IncrementalEditValidation.None) {
// return;
//}
//// Get syntactic errors (to force a refresh)
if (incrSyntaxErrs !== fullSyntaxErrs) {
throw new Error('Mismatched incremental/full syntactic errors for file ' + this.activeFile.fileName + '.\n=== Incremental errors ===\n' + incrSyntaxErrs + '\n=== Full Errors ===\n' + fullSyntaxErrs);
}
//var incrSyntaxErrs = JSON.stringify(this.languageService.getSyntacticDiagnostics(this.activeFile.fileName));
//// Check syntactic structure
//var snapshot = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName);
if (this.editValidation !== IncrementalEditValidation.SyntacticOnly) {
var compiler = new TypeScript.TypeScriptCompiler();
for (var i = 0; i < this.testData.files.length; i++) {
snapshot = this.languageServiceShimHost.getScriptSnapshot(this.testData.files[i].fileName);
compiler.addFile(this.testData.files[i].fileName, TypeScript.ScriptSnapshot.fromString(snapshot.getText(0, snapshot.getLength())), TypeScript.ByteOrderMark.None, "0", true);
}
//var content = snapshot.getText(0, snapshot.getLength());
//var refSyntaxTree = TypeScript.Parser.parse(this.activeFile.fileName, TypeScript.SimpleText.fromString(content), ts.ScriptTarget.ES5, TypeScript.isDTSFile(this.activeFile.fileName));
//var fullSyntaxErrs = JSON.stringify(refSyntaxTree.diagnostics());
//if (incrSyntaxErrs !== fullSyntaxErrs) {
// throw new Error('Mismatched incremental/full syntactic errors for file ' + this.activeFile.fileName + '.\n=== Incremental errors ===\n' + incrSyntaxErrs + '\n=== Full Errors ===\n' + fullSyntaxErrs);
//}
compiler.addFile('lib.d.ts', TypeScript.ScriptSnapshot.fromString(Harness.Compiler.libTextMinimal), TypeScript.ByteOrderMark.None, "0", true);
// if (this.editValidation !== IncrementalEditValidation.SyntacticOnly) {
for (var i = 0; i < this.testData.files.length; i++) {
var refSemanticErrs = JSON.stringify(compiler.getSemanticDiagnostics(this.testData.files[i].fileName));
var incrSemanticErrs = JSON.stringify(this.languageService.getSemanticDiagnostics(this.testData.files[i].fileName));
// var compiler = new TypeScript.TypeScriptCompiler();
// for (var i = 0; i < this.testData.files.length; i++) {
// snapshot = this.languageServiceShimHost.getScriptSnapshot(this.testData.files[i].fileName);
// compiler.addFile(this.testData.files[i].fileName, TypeScript.ScriptSnapshot.fromString(snapshot.getText(0, snapshot.getLength())), ts.ByteOrderMark.None, 0, true);
if (incrSemanticErrs !== refSemanticErrs) {
throw new Error('Mismatched incremental/full semantic errors for file ' + this.testData.files[i].fileName + '\n=== Incremental errors ===\n' + incrSemanticErrs + '\n=== Full Errors ===\n' + refSemanticErrs);
}
}
}
// }
// compiler.addFile('lib.d.ts', TypeScript.ScriptSnapshot.fromString(Harness.Compiler.libTextMinimal), ts.ByteOrderMark.None, 0, true);
// for (var i = 0; i < this.testData.files.length; i++) {
// var refSemanticErrs = JSON.stringify(compiler.getSemanticDiagnostics(this.testData.files[i].fileName));
// var incrSemanticErrs = JSON.stringify(this.languageService.getSemanticDiagnostics(this.testData.files[i].fileName));
@@ -1207,18 +1167,18 @@ module FourSlash {
private fixCaretPosition() {
// The caret can potentially end up between the \r and \n, which is confusing. If
// that happens, move it back one character
private applyEdits(fileName: string, edits: TypeScript.Services.TextChange[], isFormattingEdit = false): number {
if (this.currentCaretPosition > 0) {
var ch = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(this.currentCaretPosition - 1, this.currentCaretPosition);
if (ch === '\r') {
this.currentCaretPosition--;
edits = edits.sort((a, b) => a.span.start() - b.span.start());
}
};
}
private applyEdits(fileName: string, edits: ts.TextEdit[], isFormattingEdit = false): number {
this.languageServiceShimHost.editScript(fileName, edits[j].span.start() + runningOffset, edits[j].span.end() + runningOffset, edits[j].newText);
this.updateMarkersForEdit(fileName, edits[j].span.start() + runningOffset, edits[j].span.end() + runningOffset, edits[j].newText);
var change = (edits[j].span.start() - edits[j].span.end()) + edits[j].newText.length;
// We get back a set of edits, but langSvc.editScript only accepts one at a time. Use this to keep track
// of the incremental offest from each edit to the next. Assumption is that these edit ranges don't overlap
var runningOffset = 0;
edits = edits.sort((a, b) => a.minChar - b.minChar);
// Get a snapshot of the content of the file so we can make sure any formatting edits didn't destroy non-whitespace characters
var snapshot = this.languageServiceShimHost.getScriptSnapshot(fileName);
@@ -1238,7 +1198,7 @@ module FourSlash {
if (newContent.replace(/\s/g, '') !== oldContent.replace(/\s/g, '')) {
throw new Error('Formatting operation destroyed non-whitespace content');
var edits = this.languageService.getFormattingEditsForDocument(this.activeFile.fileName, this.formatCodeOptions);
}
}
return runningOffset;
}
@@ -1295,7 +1255,7 @@ module FourSlash {
var definitions = this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition);
if (!definitions || !definitions.length) {
throw new Error('goToDefinition failed - expected to at least one defintion location but got 0');
this.currentCaretPosition = definition.textSpan.start();
}
if (definitionIndex >= definitions.length) {
throw new Error('goToDefinition failed - definitionIndex value (' + definitionIndex + ') exceeds definition list size (' + definitions.length + ')');
@@ -1331,7 +1291,7 @@ module FourSlash {
return this.testData.ranges.slice(0);
}
throw new Error('verifyCaretAtMarker failed - expected to be at marker "/*' + markerName + '*' + '/, but was at position ' + this.currentCaretPosition + '(' + this.getLineColStringAtCaret() + ')');
public verifyCaretAtMarker(markerName = '') {
this.taoInvalidReason = 'verifyCaretAtMarker NYI';
var pos = this.getMarkerByName(markerName);
@@ -1401,7 +1361,7 @@ module FourSlash {
public verifyCurrentNameOrDottedNameSpanText(text: string) {
this.taoInvalidReason = 'verifyCurrentNameOrDottedNameSpanText NYI';
var actual = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(span.start(), span.end());
var span = this.languageService.getNameOrDottedNameSpan(this.activeFile.fileName, this.currentCaretPosition, this.currentCaretPosition);
if (span === null) {
throw new Error('verifyCurrentNameOrDottedNameSpanText\n' +
@@ -1413,7 +1373,7 @@ module FourSlash {
if (actual !== text) {
throw new Error('verifyCurrentNameOrDottedNameSpanText\n' +
'\tExpected: "' + text + '"\n' +
resultString = resultString + this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(spanInfo.start(), spanInfo.end());
'\t Actual: "' + actual + '"');
}
}
@@ -1431,7 +1391,8 @@ module FourSlash {
Harness.Baseline.runBaseline(
"Name OrDottedNameSpans for " + this.activeFile.fileName,
});
this.testData.globalOptions['BaselineFile'],
() => {
var fileLength = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getLength();
var resultString = "";
for (var pos = 0; pos < fileLength; pos++) {
@@ -1441,7 +1402,7 @@ module FourSlash {
},
true /* run immediately */);
}
var actual = this.languageService.getOutliningSpans(this.activeFile.fileName);
public printNameOrDottedNameSpans(pos: number) {
Harness.IO.log(this.getNameOrDottedNameSpan(pos));
}
@@ -1450,27 +1411,8 @@ module FourSlash {
this.taoInvalidReason = 'verifyOutliningSpans NYI';
var actual = this.languageService.getOutliningRegions(this.activeFile.fileName);
if (expectedSpan.start !== actualSpan.textSpan.start() || expectedSpan.end !== actualSpan.textSpan.end()) {
throw new Error('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualSpan.textSpan.start() + ',' + actualSpan.textSpan.end() + ')');
}
}
}
public verifyTodoComments(descriptors: string[], spans: TextSpan[]) {
var actual = this.languageService.getTodoComments(this.activeFile.fileName,
descriptors.map(d => new TypeScript.Services.TodoCommentDescriptor(d, 0)));
if (actual.length !== spans.length) {
throw new Error('verifyTodoComments failed - expected total spans to be ' + spans.length + ', but was ' + actual.length);
}
for (var i = 0; i < spans.length; i++) {
var expectedSpan = spans[i];
var actualComment = actual[i];
var actualCommentSpan = new TypeScript.TextSpan(actualComment.position, actualComment.message.length);
if (expectedSpan.start !== actualCommentSpan.start() || expectedSpan.end !== actualCommentSpan.end()) {
throw new Error('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualCommentSpan.start() + ',' + actualCommentSpan.end() + ')');
if (actual.length !== spans.length) {
throw new Error('verifyOutliningSpans failed - expected total spans to be ' + spans.length + ', but was ' + actual.length);
}
@@ -1485,9 +1427,9 @@ module FourSlash {
public verifyMatchingBracePosition(bracePosition: number, expectedMatchPosition: number) {
this.taoInvalidReason = 'verifyMatchingBracePosition NYI';
if (bracePosition == actual[0].start()) {
var actual = this.languageService.getBraceMatchingAtPosition(this.activeFile.fileName, bracePosition);
} else if (bracePosition == actual[1].start()) {
if (actual.length !== 2) {
throw new Error('verifyMatchingBracePosition failed - expected result to contain 2 spans, but it had ' + actual.length);
}
@@ -1512,7 +1454,7 @@ module FourSlash {
var actual = this.languageService.getBraceMatchingAtPosition(this.activeFile.fileName, bracePosition);
if (actual.length !== 0) {
var referenceLanguageServiceShimHost = new Harness.TypeScriptLS();
throw new Error('verifyNoMatchingBracePosition failed - expected: 0 spans, actual: ' + actual.length);
}
}
@@ -1528,7 +1470,7 @@ module FourSlash {
referenceLanguageServiceShimHost.addScript('lib.d.ts', Harness.Compiler.libTextMinimal);
for (var i = 0; i < this.testData.files.length; i++) {
var nameOf = (type: TypeScript.Services.TypeInfo) => type ? type.fullSymbolName : '(none)';
var file = this.testData.files[i];
var snapshot = this.languageServiceShimHost.getScriptSnapshot(file.fileName);
var content = snapshot.getText(0, snapshot.getLength());
@@ -1571,14 +1513,16 @@ module FourSlash {
var positionDescription = 'Position ' + positions[i] + ' ("' + textAtPosition + '"...)';
if (anyFailed) {
/// Check number of navigationItems which match both searchValue and matchKind.
/// Report an error if expected value and actual value do not match.
throw new Error('Exception thrown in language service for ' + positionDescription + '\r\n' + errMsg);
} else if (refName !== pullName) {
throw new Error('Pull/Full disagreement failed at ' + positionDescription + ' - expected full typecheck type "' + refName + '" to equal pull type "' + pullName + '".');
}
}
}
}
/*
var item: TypeScript.Services.NavigateToItem = null;
Check number of navigationItems which match both searchValue and matchKind.
Report an error if expected value and actual value do not match.
*/
public verifyNavigationItemsCount(expected: number, searchValue: string, matchKind?: string) {
@@ -1593,8 +1537,10 @@ module FourSlash {
item = items[i];
if (!matchKind || item.matchKind === matchKind) {
actual++;
/// Verify that returned navigationItems from getNavigateToItems have matched searchValue, matchKind, and kind.
/// Report an error if getNavigateToItems does not find any matched searchValue.
}
}
if (expected != actual) {
throw new Error('verifyNavigationItemsCount failed - found: ' + actual + ' navigation items, expected: ' + expected + '.');
}
}
@@ -1630,61 +1576,70 @@ module FourSlash {
// if there was an explicit match kind specified, then it should be validated.
if (matchKind !== undefined) {
var items = this.languageService.getNavigationBarItems(this.activeFile.fileName);
var actual = this.getNavigationBarItemsCount(items);
var missingItem = { name: name, kind: kind, searchValue: searchValue, matchKind: matchKind, fileName: fileName, parentName: parentName };
throw new Error('verifyNavigationItemsListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(items) + ')');
}
}
public verifyGetScriptLexicalStructureListCount(expected: number) {
this.taoInvalidReason = 'verifyNavigationItemsListContains impossible';
private getNavigationBarItemsCount(items: TypeScript.Services.NavigationBarItem[]) {
var result = 0;
if (items) {
for (var i = 0, n = items.length; i < n; i++) {
result++;
result += this.getNavigationBarItemsCount(items[i].childItems);
}
}
return result;
}
var items = this.languageService.getScriptLexicalStructure(this.activeFile.fileName);
var actual = (items && items.length) || 0;
if (expected != actual) {
throw new Error('verifyGetScriptLexicalStructureListCount failed - found: ' + actual + ' navigation items, expected: ' + expected + '.');
}
}
public verifGetScriptLexicalStructureListContains(
var items = this.languageService.getNavigationBarItems(this.activeFile.fileName);
name: string,
kind: string,
fileName?: string,
parentName?: string,
isAdditionalSpan?: boolean,
markerPosition?: number) {
if (this.navigationBarItemsContains(items, name, kind)) {
return;
}
var missingItem = { name: name, kind: kind };
throw new Error('verifyGetScriptLexicalStructureListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(items) + ')');
}
private navigationBarItemsContains(items: TypeScript.Services.NavigationBarItem[], name: string, kind: string) {
if (items) {
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (item && item.text === name && item.kind === kind) {
return true;
this.taoInvalidReason = 'verifGetScriptLexicalStructureListContains impossible';
var items = this.languageService.getScriptLexicalStructure(this.activeFile.fileName);
if (!items || items.length === 0) {
throw new Error('verifyGetScriptLexicalStructureListContains failed - found 0 navigation items, expected at least one.');
}
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (item && item.name === name && item.kind === kind &&
(fileName === undefined || item.fileName === fileName) &&
(parentName === undefined || item.containerName === parentName)) {
if (markerPosition !== undefined || isAdditionalSpan !== undefined) {
if (isAdditionalSpan) {
if (item.additionalSpans &&
item.additionalSpans.some(span => span.minChar <= markerPosition && markerPosition <= span.limChar)) {
// marker is in an additional span for this item.
return;
}
else {
throw new Error(
'verifGetScriptLexicalStructureListContains failed - ' +
'no additional span was found that contained the position: ' + JSON.stringify(markerPosition) +
' in the item: ' + JSON.stringify(item));
}
}
else if (!isAdditionalSpan) {
if (item.minChar <= markerPosition &&
markerPosition <= item.minChar) {
// marker is in span normal item's span
return;
}
if (this.navigationBarItemsContains(item.childItems, name, kind)) {
return true;
else {
throw new Error(
'verifGetScriptLexicalStructureListContains failed - ' +
'marker was positioned: ' + JSON.stringify(markerPosition) +
' which is not in the item: ' + JSON.stringify(item));
}
return false;
}
}
else {
return;
}
}
@@ -1700,14 +1655,14 @@ module FourSlash {
var length = items && items.length;
Harness.IO.log('NavigationItems list (' + length + ' items)');
var items = this.languageService.getNavigationBarItems(this.activeFile.fileName);
for (var i = 0; i < length; i++) {
var item = items[i];
Harness.IO.log('name: ' + item.name + ', kind: ' + item.kind + ', parentName: ' + item.containerName + ', fileName: ' + item.fileName);
}
}
Harness.IO.log('name: ' + item.text + ', kind: ' + item.kind);
public printScriptLexicalStructureItems() {
var items = this.languageService.getScriptLexicalStructure(this.activeFile.fileName);
var length = items && items.length;
@@ -1726,7 +1681,7 @@ module FourSlash {
public verifyOccurrencesAtPositionListContains(fileName: string, start: number, end: number, isWriteAccess?: boolean) {
this.taoInvalidReason = 'verifyOccurrencesAtPositionListContains NYI';
if (occurance && occurance.fileName === fileName && occurance.textSpan.start() === start && occurance.textSpan.end() === end) {
var occurances = this.getOccurancesAtCurrentPosition();
if (!occurances || occurances.length === 0) {
throw new Error('verifyOccurancesAtPositionListContains failed - found 0 references, expected at least one.');
@@ -1798,7 +1753,7 @@ module FourSlash {
if (result.line >= 0) {
result.line++;
}
private assertItemInCompletionList(items: TypeScript.Services.CompletionEntry[], name: string, type?: string, docComment?: string, fullSymbolName?: string, kind?: string) {
if (result.character >= 0) {
result.character++;
}
@@ -1940,7 +1895,6 @@ module FourSlash {
fsOutput.reset();
fsErrors.reset();
harnessCompiler.compile();
var harnessCompiler = Harness.Compiler.getCompiler();
harnessCompiler.reset();
-48
View File
@@ -1,48 +0,0 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
/// <reference path="fourslash.ts" />
var testList: string[] = [];
if (IO.arguments.length === 0) {
IO.dir(Harness.userSpecifiedroot + 'tests/ls/fourslash', /\.ts$/).forEach(fn => {
if (!fn.match(/fourslash.ts$/i)) {
testList.push(fn);
}
});
} else {
IO.arguments.forEach(tests => tests.split(',').forEach(test => {
testList.push(test);
}));
}
var passCount = 0, failCount = 0;
testList.forEach(test => {
try {
IO.print('Running ' + test.substr(IO.dirName(test).length + 1) + '... ');
FourSlash.runFourSlashTest(test);
IO.printLine('passed.');
passCount++;
} catch (e) {
IO.printLine(e);
if (e.stack) {
IO.printLine(e.stack);
}
failCount++;
}
});
IO.printLine(passCount + ' passed, ' + failCount + ' failed.');
+6 -9
View File
@@ -429,25 +429,21 @@ module Harness {
module Harness {
var typescriptServiceFileName = "typescriptServices.js";
// Services files are exported because we need to eval them at global scope in order for them to be available everywhere
export var typescriptServiceFile: string;
var tcServicesFilename = "services.js";
var tcServicesFilename = "typescriptServices.js";
export var libFolder: string;
switch (Utils.getExecutionEnvironment()) {
case Utils.ExecutionEnvironment.CScript:
libFolder = Path.filePath(global['WScript'].ScriptFullName);
tcServicesFilename = "built/local/services.js";
tcServicesFilename = "built/local/typescriptServices.js";
break;
case Utils.ExecutionEnvironment.Node:
libFolder = (__dirname + '/');
tcServicesFilename = "built/local/services.js";
tcServicesFilename = "built/local/typescriptServices.js";
break;
case Utils.ExecutionEnvironment.Browser:
libFolder = "bin/";
tcServicesFilename = "built/local/services.js";
tcServicesFilename = "built/local/typescriptServices.js";
break;
default:
throw new Error('Unknown context');
@@ -557,7 +553,8 @@ module Harness {
getDefaultLibFilename: () => 'lib.d.ts',
writeFile: writeFile,
getCanonicalFileName: ts.getCanonicalFileName,
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
getNewLine: ()=> sys.newLine
}
}
+127 -86
View File
@@ -1,10 +1,13 @@
module Harness.LanguageService {
/// <reference path='..\services\services.ts' />
/// <reference path='..\services\shims.ts' />
module Harness.LanguageService {
export class ScriptInfo {
public version: number = 1;
public editRanges: { length: number; textChangeRange: TypeScript.TextChangeRange; }[] = [];
public lineMap: TypeScript.LineMap = null;
constructor(public fileName: string, public content: string, public isOpen = true, public byteOrderMark: TypeScript.ByteOrderMark = TypeScript.ByteOrderMark.None) {
constructor(public fileName: string, public content: string, public isOpen = true, public byteOrderMark: ts.ByteOrderMark = ts.ByteOrderMark.None) {
this.setContent(content);
}
@@ -51,7 +54,7 @@
}
}
class ScriptSnapshotShim implements TypeScript.Services.IScriptSnapshotShim {
class ScriptSnapshotShim implements ts.ScriptSnapshotShim {
private lineMap: TypeScript.LineMap = null;
private textSnapshot: string;
private version: number;
@@ -77,9 +80,8 @@
return JSON.stringify(this.lineMap.lineStarts());
}
public getChangeRange(oldScript: TypeScript.Services.IScriptSnapshotShim): string {
var oldShim = <ScriptSnapshotShim>oldScript;
var range = this.scriptInfo.getTextChangeRangeBetweenVersions(oldShim.version, this.version);
public getTextChangeRangeSinceVersion(scriptVersion: number): string {
var range = this.scriptInfo.getTextChangeRangeBetweenVersions(scriptVersion, this.version);
if (range === null) {
return null;
}
@@ -88,14 +90,91 @@
}
}
export class TypeScriptLS implements TypeScript.Services.ILanguageServiceShimHost {
IO = TypeScript.Environment ? TypeScript.Environment : Network.getEnvironment();
private ls: TypeScript.Services.ILanguageServiceShim = null;
class CancellationToken {
public static None: CancellationToken = new CancellationToken(null)
constructor(private cancellationToken: ts.CancellationToken) {
}
public isCancellationRequested() {
return this.cancellationToken && this.cancellationToken.isCancellationRequested();
}
}
class ScriptSnapshotShimAdapter implements TypeScript.IScriptSnapshot {
private lineStartPositions: number[] = null;
constructor(private scriptSnapshotShim: ts.ScriptSnapshotShim) {}
getText(start: number, end: number): string {return this.scriptSnapshotShim.getText(start, end);}
getLength(): number {return this.scriptSnapshotShim.getLength();}
getLineStartPositions(): number[] { return JSON.parse(this.scriptSnapshotShim.getLineStartPositions()); }
getTextChangeRangeSinceVersion(scriptVersion: number): TypeScript.TextChangeRange {
var encoded = this.scriptSnapshotShim.getTextChangeRangeSinceVersion(scriptVersion);
if (encoded == null) {
return null;
}
var decoded: { span: { start: number; length: number; }; newLength: number; } = JSON.parse(encoded);
return new TypeScript.TextChangeRange(
new TypeScript.TextSpan(decoded.span.start, decoded.span.length), decoded.newLength);
}
}
class LanguageServiceShimHostAdapter implements ts.LanguageServiceHost {
constructor(private shimHost: ts.LanguageServiceShimHost) { }
information(): boolean { return this.shimHost.information(); }
debug(): boolean { return this.shimHost.debug(); }
warning(): boolean { return this.shimHost.warning();}
error(): boolean { return this.shimHost.error(); }
fatal(): boolean { return this.shimHost.fatal(); }
log(s: string): void { this.shimHost.log(s); }
getCompilationSettings(): ts.CompilerOptions { return JSON.parse(this.shimHost.getCompilationSettings()); }
getScriptFileNames(): string[] { return JSON.parse(this.shimHost.getScriptFileNames());}
getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot { return new ScriptSnapshotShimAdapter(this.shimHost.getScriptSnapshot(fileName));}
getScriptVersion(fileName: string): number { return this.shimHost.getScriptVersion(fileName);}
getScriptIsOpen(fileName: string): boolean { return this.shimHost.getScriptIsOpen(fileName); }
getScriptByteOrderMark(fileName: string): ts.ByteOrderMark { return this.shimHost.getScriptByteOrderMark(fileName);}
getLocalizedDiagnosticMessages(): any { JSON.parse(this.shimHost.getLocalizedDiagnosticMessages());}
getCancellationToken(): ts.CancellationToken { return this.shimHost.getCancellationToken(); }
}
export class NonCachingDocumentRegistry implements ts.DocumentRegistry {
public static Instance: ts.DocumentRegistry = new NonCachingDocumentRegistry();
public acquireDocument(
fileName: string,
compilationSettings: ts.CompilerOptions,
scriptSnapshot: TypeScript.IScriptSnapshot,
byteOrderMark: ts.ByteOrderMark,
version: number,
isOpen: boolean,
referencedFiles: string[]= []): ts.Document {
return ts.createDocument(compilationSettings, fileName, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles);
}
public updateDocument(
document: ts.Document,
fileName: string,
compilationSettings: ts.CompilerOptions,
scriptSnapshot: TypeScript.IScriptSnapshot,
version: number,
isOpen: boolean,
textChangeRange: TypeScript.TextChangeRange
): ts.Document {
return document.update(scriptSnapshot, version, isOpen, textChangeRange);
}
public releaseDocument(fileName: string, compilationSettings: ts.CompilerOptions): void {
// no op since this class doesn't cache anything
}
}
export class TypeScriptLS implements ts.LanguageServiceShimHost {
private ls: ts.LanguageServiceShim = null;
public newLS: ts.LanguageService;
private fileNameToScript = new TypeScript.StringHashTable<ScriptInfo>();
private fileNameToScript: ts.Map<ScriptInfo> = {};
constructor(private cancellationToken: TypeScript.ICancellationToken = TypeScript.CancellationToken.None) {
constructor(private cancellationToken: ts.CancellationToken = CancellationToken.None) {
}
public addDefaultLibrary() {
@@ -107,17 +186,16 @@
}
public addFile(fileName: string) {
var code = Harness.Environment.readFile(fileName);
var code = Harness.IO.readFile(fileName);
this.addScript(fileName, code);
}
private getScriptInfo(fileName: string): ScriptInfo {
return this.fileNameToScript.lookup(fileName);
return this.fileNameToScript[fileName];
}
public addScript(fileName: string, content: string) {
var script = new ScriptInfo(fileName, content);
this.fileNameToScript.add(fileName, script);
this.fileNameToScript[fileName] = new ScriptInfo(fileName, content);
}
public updateScript(fileName: string, content: string) {
@@ -155,91 +233,64 @@
}
//////////////////////////////////////////////////////////////////////
// ILanguageServiceShimHost implementation
// LanguageServiceShimHost implementation
//
/// Returns json for Tools.CompilationSettings
public getCompilationSettings(): string {
return ""; // i.e. default settings
return JSON.stringify({}); // i.e. default settings
}
public getCancellationToken(): TypeScript.ICancellationToken {
public getCancellationToken(): ts.CancellationToken {
return this.cancellationToken;
}
public getScriptFileNames(): string {
return JSON.stringify(this.fileNameToScript.getAllKeys());
var fileNames: string[] = [];
ts.forEachKey(this.fileNameToScript, (fileName) => { fileNames.push(fileName); });
return JSON.stringify(fileNames);
}
public getScriptSnapshot(fileName: string): TypeScript.Services.IScriptSnapshotShim {
public getScriptSnapshot(fileName: string): ts.ScriptSnapshotShim {
return new ScriptSnapshotShim(this.getScriptInfo(fileName));
}
public getScriptVersion(fileName: string): string {
return this.getScriptInfo(fileName).version.toString();
public getScriptVersion(fileName: string): number {
return this.getScriptInfo(fileName).version;
}
public getScriptIsOpen(fileName: string): boolean {
return this.getScriptInfo(fileName).isOpen;
}
public getScriptByteOrderMark(fileName: string): TypeScript.ByteOrderMark {
public getScriptByteOrderMark(fileName: string): ts.ByteOrderMark {
return this.getScriptInfo(fileName).byteOrderMark;
}
public getDiagnosticsObject(): TypeScript.Services.ILanguageServicesDiagnostics {
return new LanguageServicesDiagnostics("");
}
public getLocalizedDiagnosticMessages(): string {
return "";
}
public fileExists(s: string) {
return this.IO.fileExists(s);
}
public directoryExists(s: string) {
return this.IO.directoryExists(s);
}
public resolveRelativePath(path: string, directory: string): string {
if (TypeScript.isRooted(path) || !directory) {
return this.IO.absolutePath(path);
}
else {
return this.IO.absolutePath(TypeScript.IOUtils.combine(directory, path));
}
}
public getParentDirectory(path: string): string {
return this.IO.directoryName(path);
return JSON.stringify({});
}
/** Return a new instance of the language service shim, up-to-date wrt to typecheck.
* To access the non-shim (i.e. actual) language service, use the "ls.languageService" property.
*/
public getLanguageService(): TypeScript.Services.ILanguageServiceShim {
public getLanguageService(): ts.LanguageServiceShim {
var ls = new TypeScript.Services.TypeScriptServicesFactory().createLanguageServiceShim(this);
this.ls = ls;
var hostAdapter = new ts.LanguageServiceShimHostAdapter(this);
this.newLS = ts.createLanguageService(hostAdapter);
var hostAdapter = new LanguageServiceShimHostAdapter(this);
this.newLS = ts.createLanguageService(hostAdapter, NonCachingDocumentRegistry.Instance);
return ls;
}
/** Parse file given its source text */
public parseSourceText(fileName: string, sourceText: TypeScript.IScriptSnapshot): TypeScript.SourceUnitSyntax {
var compilationSettings = new TypeScript.CompilationSettings();
compilationSettings.codeGenTarget = TypeScript.LanguageVersion.EcmaScript5;
var settings = TypeScript.ImmutableCompilationSettings.fromCompilationSettings(compilationSettings);
var parseOptions = settings.codeGenTarget();
return TypeScript.Parser.parse(fileName, TypeScript.SimpleText.fromScriptSnapshot(sourceText), parseOptions, TypeScript.isDTSFile(fileName)).sourceUnit();
return TypeScript.Parser.parse(fileName, TypeScript.SimpleText.fromScriptSnapshot(sourceText), ts.ScriptTarget.ES5, TypeScript.isDTSFile(fileName)).sourceUnit();
}
/** Parse a file on disk given its fileName */
public parseFile(fileName: string) {
var sourceText = TypeScript.ScriptSnapshot.fromString(this.IO.readFile(fileName, /*codepage:*/ null).contents)
var sourceText = TypeScript.ScriptSnapshot.fromString(Harness.IO.readFile(fileName))
return this.parseSourceText(fileName, sourceText);
}
@@ -248,7 +299,7 @@
* @param col 1 based index
*/
public lineColToPosition(fileName: string, line: number, col: number): number {
var script: ScriptInfo = this.fileNameToScript.lookup(fileName);
var script: ScriptInfo = this.fileNameToScript[fileName];
assert.isNotNull(script);
assert.isTrue(line >= 1);
assert.isTrue(col >= 1);
@@ -261,7 +312,7 @@
* @param col 0 based index
*/
public positionToZeroBasedLineCol(fileName: string, position: number): TypeScript.ILineAndCharacter {
var script: ScriptInfo = this.fileNameToScript.lookup(fileName);
var script: ScriptInfo = this.fileNameToScript[fileName];
assert.isNotNull(script);
var result = script.lineMap.getLineAndCharacterFromPosition(position);
@@ -272,10 +323,10 @@
}
/** Verify that applying edits to sourceFileName result in the content of the file baselineFileName */
public checkEdits(sourceFileName: string, baselineFileName: string, edits: TypeScript.Services.TextChange[]) {
var script = Utils.readFile(sourceFileName);
var formattedScript = this.applyEdits(script.contents, edits);
var baseline = Utils.readFile(baselineFileName).contents;
public checkEdits(sourceFileName: string, baselineFileName: string, edits: ts.TextEdit[]) {
var script = Harness.IO.readFile(sourceFileName);
var formattedScript = this.applyEdits(script, edits);
var baseline = Harness.IO.readFile(baselineFileName);
function noDiff(text1: string, text2: string) {
text1 = text1.replace(/^\s+|\s+$/g, "").replace(/\r\n?/g, "\n");
@@ -301,26 +352,26 @@
/** Apply an array of text edits to a string, and return the resulting string. */
public applyEdits(content: string, edits: TypeScript.Services.TextChange[]): string {
public applyEdits(content: string, edits: ts.TextEdit[]): string {
var result = content;
edits = this.normalizeEdits(edits);
for (var i = edits.length - 1; i >= 0; i--) {
var edit = edits[i];
var prefix = result.substring(0, edit.span.start());
var middle = edit.newText;
var suffix = result.substring(edit.span.end());
var prefix = result.substring(0, edit.minChar);
var middle = edit.text;
var suffix = result.substring(edit.limChar);
result = prefix + middle + suffix;
}
return result;
}
/** Normalize an array of edits by removing overlapping entries and sorting entries on the minChar position. */
private normalizeEdits(edits: TypeScript.Services.TextChange[]): TypeScript.Services.TextChange[] {
var result: TypeScript.Services.TextChange[] = [];
private normalizeEdits(edits: ts.TextEdit[]): ts.TextEdit[] {
var result: ts.TextEdit[] = [];
function mapEdits(edits: TypeScript.Services.TextChange[]): { edit: TypeScript.Services.TextChange; index: number; }[] {
var result: { edit: TypeScript.Services.TextChange; index: number; }[] = [];
function mapEdits(edits: ts.TextEdit[]): { edit: ts.TextEdit; index: number; }[] {
var result: { edit: ts.TextEdit; index: number; }[] = [];
for (var i = 0; i < edits.length; i++) {
result.push({ edit: edits[i], index: i });
}
@@ -328,7 +379,7 @@
}
var temp = mapEdits(edits).sort(function (a, b) {
var result = a.edit.span.start() - b.edit.span.start();
var result = a.edit.minChar - b.edit.limChar;
if (result === 0)
result = a.index - b.index;
return result;
@@ -347,7 +398,7 @@
}
var nextEdit = temp[next].edit;
var gap = nextEdit.span.start() - currentEdit.span.end();
var gap = nextEdit.minChar - currentEdit.limChar;
// non-overlapping edits
if (gap >= 0) {
@@ -359,7 +410,7 @@
// overlapping edits: for now, we only support ignoring an next edit
// entirely contained in the current edit.
if (currentEdit.span.end() >= nextEdit.span.end()) {
if (currentEdit.minChar >= nextEdit.limChar) {
next++;
continue;
}
@@ -371,15 +422,5 @@
return result;
}
}
export class LanguageServicesDiagnostics implements TypeScript.Services.ILanguageServicesDiagnostics {
constructor(private destination: string) { }
public log(content: string): void {
//Imitates the LanguageServicesDiagnostics object when not in Visual Studio
}
}
}
+2 -1
View File
@@ -223,7 +223,8 @@ class ProjectRunner extends RunnerBase {
writeFile: writeFile,
getCurrentDirectory: getCurrentDirectory,
getCanonicalFileName: ts.getCanonicalFileName,
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
getNewLine:()=> sys.newLine
};
}
+4 -7
View File
@@ -62,12 +62,10 @@ if (testConfigFile !== '') {
runners.push(new ProjectRunner());
break;
case 'fourslash':
// TODO: Re-enable Fourslash tests
// runners.push(new FourslashRunner());
runners.push(new FourslashRunner());
break;
case 'fourslash-generated':
// TODO: Re-enable Fourslash tests
// runners.push(new GeneratedFourslashRunner());
runners.push(new GeneratedFourslashRunner());
break;
case 'unittests':
runners.push(new UnitTestRunner(UnittestTestType.Compiler));
@@ -99,9 +97,8 @@ if (runners.length === 0) {
}
//// language services
// TODO: Re-enable Fourslash runner
// runners.push(new FourslashRunner());
// runners.push(new GeneratedFourslashRunner());
runners.push(new FourslashRunner());
//runners.push(new GeneratedFourslashRunner());
}
sys.newLine = '\r\n';
+2 -1
View File
@@ -112,7 +112,8 @@ module RWC {
getDefaultLibFilename: () => libPath,
writeFile: (fn, contents) => emitterIOHost.writeFile(fn, contents, false),
getCanonicalFileName: ts.getCanonicalFileName,
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
getNewLine: () => sys.newLine
};
var resolvedProgram = ts.createProgram(opts.filenames, opts.options, host);
+116
View File
@@ -0,0 +1,116 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='references.ts' />
module TypeScript.Services {
export class BraceMatcher {
// Given a script name and position in the script, return a pair of text range if the
// position corresponds to a "brace matchin" characters (e.g. "{" or "(", etc.)
// If the position is not on any range, return an empty set.
public static getMatchSpans(syntaxTree: TypeScript.SyntaxTree, position: number): TypeScript.TextSpan[] {
var result: TypeScript.TextSpan[] = [];
var currentToken = findToken(syntaxTree.sourceUnit(), position);
BraceMatcher.getMatchingCloseBrace(currentToken, position, result);
BraceMatcher.getMatchingOpenBrace(currentToken, position, result);
return result;
}
private static getMatchingCloseBrace(currentToken: TypeScript.ISyntaxToken, position: number, result: TypeScript.TextSpan[]) {
if (start(currentToken) === position) {
var closingBraceKind = BraceMatcher.getMatchingCloseBraceTokenKind(currentToken);
if (closingBraceKind !== null) {
var parentElement = currentToken.parent
var currentPosition = fullStart(currentToken.parent);
for (var i = 0, n = childCount(parentElement); i < n; i++) {
var element = childAt(parentElement, i);
if (element !== null && fullWidth(element) > 0) {
if (element.kind() === closingBraceKind) {
var range1 = new TypeScript.TextSpan(position, width(currentToken));
var range2 = new TypeScript.TextSpan(currentPosition + leadingTriviaWidth(element), width(element));
result.push(range1, range2);
break;
}
currentPosition += fullWidth(element);
}
}
}
}
}
private static getMatchingOpenBrace(currentToken: TypeScript.ISyntaxToken, position: number, result: TypeScript.TextSpan[]) {
// Check if the current token to the left is a close brace
if (currentToken.fullStart() === position) {
currentToken = previousToken(currentToken);
}
if (currentToken !== null && start(currentToken) === (position - 1)) {
var openBraceKind = BraceMatcher.getMatchingOpenBraceTokenKind(currentToken);
if (openBraceKind !== null) {
var parentElement = currentToken.parent;
var currentPosition = fullStart(currentToken.parent) + fullWidth(parentElement);
for (var i = childCount(parentElement) - 1 ; i >= 0; i--) {
var element = childAt(parentElement, i);
if (element !== null && fullWidth(element) > 0) {
if (element.kind() === openBraceKind) {
var range1 = new TypeScript.TextSpan(position - 1, width(currentToken));
var range2 = new TypeScript.TextSpan(currentPosition - lastToken(element).trailingTriviaWidth() - width(element), width(element));
result.push(range1, range2);
break;
}
currentPosition -= fullWidth(element);
}
}
}
}
}
private static getMatchingCloseBraceTokenKind(positionedElement: TypeScript.ISyntaxElement): TypeScript.SyntaxKind {
var element = positionedElement !== null && positionedElement;
switch (element.kind()) {
case TypeScript.SyntaxKind.OpenBraceToken:
return TypeScript.SyntaxKind.CloseBraceToken
case TypeScript.SyntaxKind.OpenParenToken:
return TypeScript.SyntaxKind.CloseParenToken;
case TypeScript.SyntaxKind.OpenBracketToken:
return TypeScript.SyntaxKind.CloseBracketToken;
case TypeScript.SyntaxKind.LessThanToken:
return TypeScript.SyntaxUtilities.isAngleBracket(positionedElement) ? TypeScript.SyntaxKind.GreaterThanToken : null;
}
return null;
}
private static getMatchingOpenBraceTokenKind(positionedElement: TypeScript.ISyntaxElement): TypeScript.SyntaxKind {
var element = positionedElement !== null && positionedElement;
switch (element.kind()) {
case TypeScript.SyntaxKind.CloseBraceToken:
return TypeScript.SyntaxKind.OpenBraceToken
case TypeScript.SyntaxKind.CloseParenToken:
return TypeScript.SyntaxKind.OpenParenToken;
case TypeScript.SyntaxKind.CloseBracketToken:
return TypeScript.SyntaxKind.OpenBracketToken;
case TypeScript.SyntaxKind.GreaterThanToken:
return TypeScript.SyntaxUtilities.isAngleBracket(positionedElement) ? TypeScript.SyntaxKind.LessThanToken : null;
}
return null;
}
}
}
File diff suppressed because it is too large Load Diff
+53
View File
@@ -0,0 +1,53 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='references.ts' />
module TypeScript {
export class Comment {
constructor(private _trivia: ISyntaxTrivia,
public endsLine: boolean,
public _start: number,
public _end: number) {
}
public start(): number {
return this._start;
}
public end(): number {
return this._end;
}
public fullText(): string {
return this._trivia.fullText();
}
public kind(): SyntaxKind {
return this._trivia.kind();
}
public structuralEquals(ast: Comment, includingPosition: boolean): boolean {
if (includingPosition) {
if (this.start() !== ast.start() || this.end() !== ast.end()) {
return false;
}
}
return this._trivia.fullText() === ast._trivia.fullText() &&
this.endsLine === ast.endsLine;
}
}
}
+759
View File
@@ -0,0 +1,759 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='references.ts' />
module TypeScript.ASTHelpers {
var sentinelEmptyArray: any[] = [];
//export function scriptIsElided(sourceUnit: SourceUnitSyntax): boolean {
// return isDTSFile(sourceUnit.syntaxTree.fileName()) || moduleMembersAreElided(sourceUnit.moduleElements);
//}
//export function moduleIsElided(declaration: ModuleDeclarationSyntax): boolean {
// return hasModifier(declaration.modifiers, PullElementFlags.Ambient) || moduleMembersAreElided(declaration.moduleElements);
//}
//function moduleMembersAreElided(members: IModuleElementSyntax[]): boolean {
// for (var i = 0, n = members.length; i < n; i++) {
// var member = members[i];
// // We should emit *this* module if it contains any non-interface types.
// // Caveat: if we have contain a module, then we should be emitted *if we want to
// // emit that inner module as well.
// if (member.kind() === SyntaxKind.ModuleDeclaration) {
// if (!moduleIsElided(<ModuleDeclarationSyntax>member)) {
// return false;
// }
// }
// else if (member.kind() !== SyntaxKind.InterfaceDeclaration) {
// return false;
// }
// }
// return true;
//}
//export function enumIsElided(declaration: EnumDeclarationSyntax): boolean {
// if (hasModifier(declaration.modifiers, PullElementFlags.Ambient)) {
// return true;
// }
// return false;
//}
export function isValidAstNode(ast: ISyntaxElement): boolean {
return ast && !isShared(ast) && start(ast) !== -1 && end(ast) !== -1;
}
export function isValidSpan(ast: ISpan): boolean {
if (!ast)
return false;
if (ast.start() === -1 || ast.end() === -1)
return false;
return true;
}
///
/// Return the ISyntaxElement containing "position"
///
export function getAstAtPosition(script: ISyntaxElement, pos: number, useTrailingTriviaAsLimChar: boolean = true, forceInclusive: boolean = false): ISyntaxElement {
var top: ISyntaxElement = null;
var pre = function (cur: ISyntaxElement, walker: IAstWalker) {
if (!isShared(cur) && isValidAstNode(cur)) {
var isInvalid1 = cur.kind() === SyntaxKind.ExpressionStatement && width(cur) === 0;
if (isInvalid1) {
walker.options.goChildren = false;
}
else {
// Add "cur" to the stack if it contains our position
// For "identifier" nodes, we need a special case: A position equal to "limChar" is
// valid, since the position corresponds to a caret position (in between characters)
// For example:
// bar
// 0123
// If "position === 3", the caret is at the "right" of the "r" character, which should be considered valid
var inclusive =
forceInclusive ||
cur.kind() === SyntaxKind.IdentifierName ||
cur.kind() === SyntaxKind.MemberAccessExpression ||
cur.kind() === SyntaxKind.QualifiedName ||
//cur.kind() === SyntaxKind.TypeRef ||
cur.kind() === SyntaxKind.VariableDeclaration ||
cur.kind() === SyntaxKind.VariableDeclarator ||
cur.kind() === SyntaxKind.InvocationExpression ||
pos === end(script) + lastToken(script).trailingTriviaWidth(); // Special "EOF" case
var minChar = start(cur);
var limChar = end(cur) + (useTrailingTriviaAsLimChar ? trailingTriviaWidth(cur) : 0) + (inclusive ? 1 : 0);
if (pos >= minChar && pos < limChar) {
// Ignore empty lists
if ((cur.kind() !== SyntaxKind.List && cur.kind() !== SyntaxKind.SeparatedList) || end(cur) > start(cur)) {
// TODO: Since ISyntaxElement is sometimes not correct wrt to position, only add "cur" if it's better
// than top of the stack.
if (top === null) {
top = cur;
}
else if (start(cur) >= start(top) &&
(end(cur) + (useTrailingTriviaAsLimChar ? trailingTriviaWidth(cur) : 0)) <= (end(top) + (useTrailingTriviaAsLimChar ? trailingTriviaWidth(top) : 0))) {
// this new node appears to be better than the one we're
// storing. Make this the new node.
// However, If the current top is a missing identifier, we
// don't want to replace it with another missing identifier.
// We want to return the first missing identifier found in a
// depth first walk of the tree.
if (width(top) !== 0 || width(cur) !== 0) {
top = cur;
}
}
}
}
// Don't go further down the tree if pos is outside of [minChar, limChar]
walker.options.goChildren = (minChar <= pos && pos <= limChar);
}
}
};
getAstWalkerFactory().walk(script, pre);
return top;
}
export function getExtendsHeritageClause(clauses: HeritageClauseSyntax[]): HeritageClauseSyntax {
return getHeritageClause(clauses, SyntaxKind.ExtendsHeritageClause);
}
export function getImplementsHeritageClause(clauses: HeritageClauseSyntax[]): HeritageClauseSyntax {
return getHeritageClause(clauses, SyntaxKind.ImplementsHeritageClause);
}
function getHeritageClause(clauses: HeritageClauseSyntax[], kind: SyntaxKind): HeritageClauseSyntax {
if (clauses) {
for (var i = 0, n = clauses.length; i < n; i++) {
var child = clauses[i];
if (child.typeNames.length > 0 && child.kind() === kind) {
return child;
}
}
}
return null;
}
export function isCallExpression(ast: ISyntaxElement): boolean {
return (ast && ast.kind() === SyntaxKind.InvocationExpression) ||
(ast && ast.kind() === SyntaxKind.ObjectCreationExpression);
}
export function isCallExpressionTarget(ast: ISyntaxElement): boolean {
return !!getCallExpressionTarget(ast);
}
export function getCallExpressionTarget(ast: ISyntaxElement): ISyntaxElement {
if (!ast) {
return null;
}
var current = ast;
while (current && current.parent) {
if (current.parent.kind() === SyntaxKind.MemberAccessExpression &&
(<MemberAccessExpressionSyntax>current.parent).name === current) {
current = current.parent;
continue;
}
break;
}
if (current && current.parent) {
if (current.parent.kind() === SyntaxKind.InvocationExpression || current.parent.kind() === SyntaxKind.ObjectCreationExpression) {
return current === (<InvocationExpressionSyntax>current.parent).expression ? current : null;
}
}
return null;
}
function isNameOfSomeDeclaration(ast: ISyntaxElement) {
if (ast === null || ast.parent === null) {
return false;
}
if (ast.kind() !== SyntaxKind.IdentifierName) {
return false;
}
switch (ast.parent.kind()) {
case SyntaxKind.ClassDeclaration:
return (<ClassDeclarationSyntax>ast.parent).identifier === ast;
case SyntaxKind.InterfaceDeclaration:
return (<InterfaceDeclarationSyntax>ast.parent).identifier === ast;
case SyntaxKind.EnumDeclaration:
return (<EnumDeclarationSyntax>ast.parent).identifier === ast;
case SyntaxKind.ModuleDeclaration:
return (<ModuleDeclarationSyntax>ast.parent).name === ast || (<ModuleDeclarationSyntax>ast.parent).stringLiteral === ast;
case SyntaxKind.VariableDeclarator:
return (<VariableDeclaratorSyntax>ast.parent).propertyName === ast;
case SyntaxKind.FunctionDeclaration:
return (<FunctionDeclarationSyntax>ast.parent).identifier === ast;
case SyntaxKind.MemberFunctionDeclaration:
return (<MemberFunctionDeclarationSyntax>ast.parent).propertyName === ast;
case SyntaxKind.Parameter:
return (<ParameterSyntax>ast.parent).identifier === ast;
case SyntaxKind.TypeParameter:
return (<TypeParameterSyntax>ast.parent).identifier === ast;
case SyntaxKind.SimplePropertyAssignment:
return (<SimplePropertyAssignmentSyntax>ast.parent).propertyName === ast;
case SyntaxKind.FunctionPropertyAssignment:
return (<FunctionPropertyAssignmentSyntax>ast.parent).propertyName === ast;
case SyntaxKind.EnumElement:
return (<EnumElementSyntax>ast.parent).propertyName === ast;
case SyntaxKind.ImportDeclaration:
return (<ImportDeclarationSyntax>ast.parent).identifier === ast;
case SyntaxKind.MethodSignature:
return (<MethodSignatureSyntax>ast.parent).propertyName === ast;
case SyntaxKind.PropertySignature:
return (<MethodSignatureSyntax>ast.parent).propertyName === ast;
}
return false;
}
export function isDeclarationASTOrDeclarationNameAST(ast: ISyntaxElement) {
return isNameOfSomeDeclaration(ast) || ASTHelpers.isDeclarationAST(ast);
}
export function getEnclosingParameterForInitializer(ast: ISyntaxElement): ParameterSyntax {
var current = ast;
while (current) {
switch (current.kind()) {
case SyntaxKind.EqualsValueClause:
if (current.parent && current.parent.kind() === SyntaxKind.Parameter) {
return <ParameterSyntax>current.parent;
}
break;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.ModuleDeclaration:
// exit early
return null;
}
current = current.parent;
}
return null;
}
export function getEnclosingMemberDeclaration(ast: ISyntaxElement): ISyntaxElement {
var current = ast;
while (current) {
switch (current.kind()) {
case SyntaxKind.MemberVariableDeclaration:
case SyntaxKind.MethodSignature:
case SyntaxKind.MemberFunctionDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
return current;
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.ModuleDeclaration:
// exit early
return null;
}
current = current.parent;
}
return null;
}
export function isNameOfFunction(ast: ISyntaxElement) {
return ast
&& ast.parent
&& ast.kind() === SyntaxKind.IdentifierName
&& ast.parent.kind() === SyntaxKind.FunctionDeclaration
&& (<FunctionDeclarationSyntax>ast.parent).identifier === ast;
}
export function isNameOfMemberFunction(ast: ISyntaxElement) {
return ast
&& ast.parent
&& ast.kind() === SyntaxKind.IdentifierName
&& ast.parent.kind() === SyntaxKind.MemberFunctionDeclaration
&& (<MemberFunctionDeclarationSyntax>ast.parent).propertyName === ast;
}
export function isNameOfMemberAccessExpression(ast: ISyntaxElement) {
if (ast &&
ast.parent &&
ast.parent.kind() === SyntaxKind.MemberAccessExpression &&
(<MemberAccessExpressionSyntax>ast.parent).name === ast) {
return true;
}
return false;
}
export function isRightSideOfQualifiedName(ast: ISyntaxElement) {
if (ast &&
ast.parent &&
ast.parent.kind() === SyntaxKind.QualifiedName &&
(<QualifiedNameSyntax>ast.parent).right === ast) {
return true;
}
return false;
}
export function parentIsModuleDeclaration(ast: ISyntaxElement) {
return ast.parent && ast.parent.kind() === SyntaxKind.ModuleDeclaration;
}
export function isDeclarationAST(ast: ISyntaxElement): boolean {
switch (ast.kind()) {
case SyntaxKind.VariableDeclarator:
return getVariableStatement(<VariableDeclaratorSyntax>ast) !== null;
case SyntaxKind.ImportDeclaration:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.Parameter:
case SyntaxKind.SimpleArrowFunctionExpression:
case SyntaxKind.ParenthesizedArrowFunctionExpression:
case SyntaxKind.IndexSignature:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.ArrayType:
case SyntaxKind.ObjectType:
case SyntaxKind.TypeParameter:
case SyntaxKind.ConstructorDeclaration:
case SyntaxKind.MemberFunctionDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.MemberVariableDeclaration:
case SyntaxKind.IndexMemberDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.EnumElement:
case SyntaxKind.SimplePropertyAssignment:
case SyntaxKind.FunctionPropertyAssignment:
case SyntaxKind.FunctionExpression:
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
case SyntaxKind.MethodSignature:
case SyntaxKind.PropertySignature:
return true;
default:
return false;
}
}
export function preComments(element: ISyntaxElement, text: ISimpleText): Comment[]{
if (element) {
switch (element.kind()) {
case SyntaxKind.VariableStatement:
case SyntaxKind.ExpressionStatement:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ImportDeclaration:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.IfStatement:
case SyntaxKind.SimplePropertyAssignment:
case SyntaxKind.MemberFunctionDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.ReturnStatement:
case SyntaxKind.ConstructorDeclaration:
case SyntaxKind.MemberVariableDeclaration:
case SyntaxKind.EnumElement:
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
case SyntaxKind.IndexSignature:
case SyntaxKind.PropertySignature:
case SyntaxKind.MethodSignature:
case SyntaxKind.FunctionPropertyAssignment:
case SyntaxKind.Parameter:
return convertNodeLeadingComments(element, text);
}
}
return null;
}
export function postComments(element: ISyntaxElement, text: ISimpleText): Comment[] {
if (element) {
switch (element.kind()) {
case SyntaxKind.ExpressionStatement:
return convertNodeTrailingComments(element, text, /*allowWithNewLine:*/ true);
case SyntaxKind.VariableStatement:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ImportDeclaration:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.IfStatement:
case SyntaxKind.SimplePropertyAssignment:
case SyntaxKind.MemberFunctionDeclaration:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.ReturnStatement:
case SyntaxKind.ConstructorDeclaration:
case SyntaxKind.MemberVariableDeclaration:
case SyntaxKind.EnumElement:
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
case SyntaxKind.IndexSignature:
case SyntaxKind.PropertySignature:
case SyntaxKind.MethodSignature:
case SyntaxKind.FunctionPropertyAssignment:
case SyntaxKind.Parameter:
return convertNodeTrailingComments(element, text);
}
}
return null;
}
function convertNodeTrailingComments(node: ISyntaxElement, text: ISimpleText, allowWithNewLine = false): Comment[]{
// Bail out quickly before doing any expensive math computation.
var _lastToken = lastToken(node);
if (_lastToken === null || !_lastToken.hasTrailingTrivia()) {
return null;
}
if (!allowWithNewLine && SyntaxUtilities.isLastTokenOnLine(_lastToken, text)) {
return null;
}
return convertComments(_lastToken.trailingTrivia(text), fullStart(node) + fullWidth(node) - _lastToken.trailingTriviaWidth(text));
}
function convertNodeLeadingComments(element: ISyntaxElement, text: ISimpleText): Comment[]{
if (element) {
return convertTokenLeadingComments(firstToken(element), text);
}
return null;
}
export function convertTokenLeadingComments(token: ISyntaxToken, text: ISimpleText): Comment[]{
if (token === null) {
return null;
}
return token.hasLeadingTrivia()
? convertComments(token.leadingTrivia(text), token.fullStart())
: null;
}
export function convertTokenTrailingComments(token: ISyntaxToken, text: ISimpleText): Comment[] {
if (token === null) {
return null;
}
return token.hasTrailingTrivia()
? convertComments(token.trailingTrivia(text), fullEnd(token) - token.trailingTriviaWidth(text))
: null;
}
function convertComments(triviaList: ISyntaxTriviaList, commentStartPosition: number): Comment[]{
var result: Comment[] = null;
for (var i = 0, n = triviaList.count(); i < n; i++) {
var trivia = triviaList.syntaxTriviaAt(i);
if (trivia.isComment()) {
var hasTrailingNewLine = ((i + 1) < n) && triviaList.syntaxTriviaAt(i + 1).isNewLine();
result = result || [];
result.push(convertComment(trivia, commentStartPosition, hasTrailingNewLine));
}
commentStartPosition += trivia.fullWidth();
}
return result;
}
function convertComment(trivia: ISyntaxTrivia, commentStartPosition: number, hasTrailingNewLine: boolean): Comment {
var comment = new Comment(trivia, hasTrailingNewLine, commentStartPosition, commentStartPosition + trivia.fullWidth());
return comment;
}
export function docComments(ast: ISyntaxElement, text: ISimpleText): Comment[] {
if (isDeclarationAST(ast)) {
var comments: Comment[] = null;
if (ast.kind() === SyntaxKind.VariableDeclarator) {
// Get the doc comments for a variable off of the variable statement. That's what
// they'll be attached to in the tree.
comments = TypeScript.ASTHelpers.preComments(getVariableStatement(<VariableDeclaratorSyntax>ast), text);
}
else if (ast.kind() === SyntaxKind.Parameter) {
// First check if the parameter was written like so:
// (
// /** blah */ a,
// /** blah */ b);
comments = TypeScript.ASTHelpers.preComments(ast, text);
if (!comments) {
// Now check if it was written like so:
// (/** blah */ a, /** blah */ b);
// In this case, the comment will belong to the preceding token.
var previousToken = findToken(syntaxTree(ast).sourceUnit(), firstToken(ast).fullStart() - 1);
if (previousToken && (previousToken.kind() === SyntaxKind.OpenParenToken || previousToken.kind() === SyntaxKind.CommaToken)) {
comments = convertTokenTrailingComments(previousToken, text);
}
}
}
else {
comments = TypeScript.ASTHelpers.preComments(ast, text);
}
if (comments && comments.length > 0) {
return comments.filter(c => isDocComment(c));
}
}
return sentinelEmptyArray;
}
export function isDocComment(comment: Comment) {
if (comment.kind() === SyntaxKind.MultiLineCommentTrivia) {
var fullText = comment.fullText();
return fullText.charAt(2) === "*" && fullText.charAt(3) !== "/";
}
return false;
}
export function getParameterList(ast: ISyntaxElement): ParameterListSyntax {
if (ast) {
switch (ast.kind()) {
case SyntaxKind.ConstructorDeclaration:
return getParameterList((<ConstructorDeclarationSyntax>ast).callSignature);
case SyntaxKind.FunctionDeclaration:
return getParameterList((<FunctionDeclarationSyntax>ast).callSignature);
case SyntaxKind.ParenthesizedArrowFunctionExpression:
return getParameterList((<ParenthesizedArrowFunctionExpressionSyntax>ast).callSignature);
case SyntaxKind.ConstructSignature:
return getParameterList((<ConstructSignatureSyntax>ast).callSignature);
case SyntaxKind.MemberFunctionDeclaration:
return getParameterList((<MemberFunctionDeclarationSyntax>ast).callSignature);
case SyntaxKind.FunctionPropertyAssignment:
return getParameterList((<FunctionPropertyAssignmentSyntax>ast).callSignature);
case SyntaxKind.FunctionExpression:
return getParameterList((<FunctionExpressionSyntax>ast).callSignature);
case SyntaxKind.MethodSignature:
return getParameterList((<MethodSignatureSyntax>ast).callSignature);
case SyntaxKind.ConstructorType:
return (<ConstructorTypeSyntax>ast).parameterList;
case SyntaxKind.FunctionType:
return (<FunctionTypeSyntax>ast).parameterList;
case SyntaxKind.CallSignature:
return (<CallSignatureSyntax>ast).parameterList;
case SyntaxKind.GetAccessor:
return getParameterList((<GetAccessorSyntax>ast).callSignature);
case SyntaxKind.SetAccessor:
return getParameterList((<SetAccessorSyntax>ast).callSignature);
}
}
return null;
}
export function getType(ast: ISyntaxElement): ITypeSyntax {
if (ast) {
switch (ast.kind()) {
case SyntaxKind.FunctionDeclaration:
return getType((<FunctionDeclarationSyntax>ast).callSignature);
case SyntaxKind.ParenthesizedArrowFunctionExpression:
return getType((<ParenthesizedArrowFunctionExpressionSyntax>ast).callSignature);
case SyntaxKind.ConstructSignature:
return getType((<ConstructSignatureSyntax>ast).callSignature);
case SyntaxKind.MemberFunctionDeclaration:
return getType((<MemberFunctionDeclarationSyntax>ast).callSignature);
case SyntaxKind.FunctionPropertyAssignment:
return getType((<FunctionPropertyAssignmentSyntax>ast).callSignature);
case SyntaxKind.FunctionExpression:
return getType((<FunctionExpressionSyntax>ast).callSignature);
case SyntaxKind.MethodSignature:
return getType((<MethodSignatureSyntax>ast).callSignature);
case SyntaxKind.CallSignature:
return getType((<CallSignatureSyntax>ast).typeAnnotation);
case SyntaxKind.IndexSignature:
return getType((<IndexSignatureSyntax>ast).typeAnnotation);
case SyntaxKind.PropertySignature:
return getType((<PropertySignatureSyntax>ast).typeAnnotation);
case SyntaxKind.GetAccessor:
return getType((<GetAccessorSyntax>ast).callSignature);
case SyntaxKind.Parameter:
return getType((<ParameterSyntax>ast).typeAnnotation);
case SyntaxKind.MemberVariableDeclaration:
return getType((<MemberVariableDeclarationSyntax>ast).variableDeclarator);
case SyntaxKind.VariableDeclarator:
return getType((<VariableDeclaratorSyntax>ast).typeAnnotation);
case SyntaxKind.CatchClause:
return getType((<CatchClauseSyntax>ast).typeAnnotation);
case SyntaxKind.ConstructorType:
return (<ConstructorTypeSyntax>ast).type;
case SyntaxKind.FunctionType:
return (<FunctionTypeSyntax>ast).type;
case SyntaxKind.TypeAnnotation:
return (<TypeAnnotationSyntax>ast).type;
}
}
return null;
}
function getVariableStatement(variableDeclarator: VariableDeclaratorSyntax): VariableStatementSyntax {
if (variableDeclarator && variableDeclarator.parent && variableDeclarator.parent.parent && variableDeclarator.parent.parent.parent &&
variableDeclarator.parent.kind() === SyntaxKind.SeparatedList &&
variableDeclarator.parent.parent.kind() === SyntaxKind.VariableDeclaration &&
variableDeclarator.parent.parent.parent.kind() === SyntaxKind.VariableStatement) {
return <VariableStatementSyntax>variableDeclarator.parent.parent.parent;
}
return null;
}
export function getVariableDeclaratorModifiers(variableDeclarator: VariableDeclaratorSyntax): ISyntaxToken[] {
var variableStatement = getVariableStatement(variableDeclarator);
return variableStatement ? variableStatement.modifiers : Syntax.emptyList<ISyntaxToken>();
}
export function isIntegerLiteralAST(expression: ISyntaxElement): boolean {
if (expression) {
switch (expression.kind()) {
case SyntaxKind.PlusExpression:
case SyntaxKind.NegateExpression:
// Note: if there is a + or - sign, we can only allow a normal integer following
// (and not a hex integer). i.e. -0xA is a legal expression, but it is not a
// *literal*.
expression = (<PrefixUnaryExpressionSyntax>expression).operand;
return expression.kind() === SyntaxKind.NumericLiteral && IntegerUtilities.isInteger((<ISyntaxToken>expression).text());
case SyntaxKind.NumericLiteral:
// If it doesn't have a + or -, then either an integer literal or a hex literal
// is acceptable.
var text = (<ISyntaxToken>expression).text();
return IntegerUtilities.isInteger(text) || IntegerUtilities.isHexInteger(text);
}
}
return false;
}
export function getEnclosingModuleDeclaration(ast: ISyntaxElement): ModuleDeclarationSyntax {
while (ast) {
if (ast.kind() === SyntaxKind.ModuleDeclaration) {
return <ModuleDeclarationSyntax>ast;
}
ast = ast.parent;
}
return null;
}
function isEntireNameOfModuleDeclaration(nameAST: ISyntaxElement) {
return parentIsModuleDeclaration(nameAST) && (<ModuleDeclarationSyntax>nameAST.parent).name === nameAST;
}
export function getModuleDeclarationFromNameAST(ast: ISyntaxElement): ModuleDeclarationSyntax {
if (ast) {
switch (ast.kind()) {
case SyntaxKind.StringLiteral:
if (parentIsModuleDeclaration(ast) && (<ModuleDeclarationSyntax>ast.parent).stringLiteral === ast) {
return <ModuleDeclarationSyntax>ast.parent;
}
return null;
case SyntaxKind.IdentifierName:
case SyntaxKind.QualifiedName:
if (isEntireNameOfModuleDeclaration(ast)) {
return <ModuleDeclarationSyntax>ast.parent;
}
break;
default:
return null;
}
// Only qualified names can be name of module declaration if they didnt satisfy above conditions
for (ast = ast.parent; ast && ast.kind() === SyntaxKind.QualifiedName; ast = ast.parent) {
if (isEntireNameOfModuleDeclaration(ast)) {
return <ModuleDeclarationSyntax>ast.parent;
}
}
}
return null;
}
export function isLastNameOfModule(ast: ModuleDeclarationSyntax, astName: ISyntaxElement): boolean {
if (ast) {
if (ast.stringLiteral) {
return astName === ast.stringLiteral;
}
else if (ast.name.kind() === SyntaxKind.QualifiedName) {
return astName === (<QualifiedNameSyntax>ast.name).right;
}
else {
return astName === ast.name;
}
}
return false;
}
export function getNameOfIdenfierOrQualifiedName(name: ISyntaxElement): string {
if (name.kind() === SyntaxKind.IdentifierName) {
return (<ISyntaxToken>name).text();
}
else {
Debug.assert(name.kind() == SyntaxKind.QualifiedName);
var dotExpr = <QualifiedNameSyntax>name;
return getNameOfIdenfierOrQualifiedName(dotExpr.left) + "." + getNameOfIdenfierOrQualifiedName(dotExpr.right);
}
}
export function getModuleNames(name: ISyntaxElement, result?: ISyntaxToken[]): ISyntaxToken[] {
result = result || [];
if (name.kind() === SyntaxKind.QualifiedName) {
getModuleNames((<QualifiedNameSyntax>name).left, result);
result.push((<QualifiedNameSyntax>name).right);
}
else {
result.push(<ISyntaxToken>name);
}
return result;
}
}
+716
View File
@@ -0,0 +1,716 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='references.ts' />
module TypeScript {
function walkListChildren(preAst: ISyntaxNodeOrToken[], walker: AstWalker): void {
for (var i = 0, n = preAst.length; i < n; i++) {
walker.walk(preAst[i]);
}
}
function walkThrowStatementChildren(preAst: ThrowStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
}
function walkPrefixUnaryExpressionChildren(preAst: PrefixUnaryExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.operand);
}
function walkPostfixUnaryExpressionChildren(preAst: PostfixUnaryExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.operand);
}
function walkDeleteExpressionChildren(preAst: DeleteExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
}
function walkTypeArgumentListChildren(preAst: TypeArgumentListSyntax, walker: AstWalker): void {
walker.walk(preAst.typeArguments);
}
function walkTypeOfExpressionChildren(preAst: TypeOfExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
}
function walkVoidExpressionChildren(preAst: VoidExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
}
function walkArgumentListChildren(preAst: ArgumentListSyntax, walker: AstWalker): void {
walker.walk(preAst.typeArgumentList);
walker.walk(preAst.arguments);
}
function walkArrayLiteralExpressionChildren(preAst: ArrayLiteralExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.expressions);
}
function walkSimplePropertyAssignmentChildren(preAst: SimplePropertyAssignmentSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyName);
walker.walk(preAst.expression);
}
function walkFunctionPropertyAssignmentChildren(preAst: FunctionPropertyAssignmentSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyName);
walker.walk(preAst.callSignature);
walker.walk(preAst.block);
}
function walkGetAccessorChildren(preAst: GetAccessorSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyName);
walker.walk(preAst.callSignature);
walker.walk(preAst.block);
}
function walkSeparatedListChildren(preAst: ISyntaxNodeOrToken[], walker: AstWalker): void {
for (var i = 0, n = preAst.length; i < n; i++) {
walker.walk(preAst[i]);
}
}
function walkSetAccessorChildren(preAst: SetAccessorSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyName);
walker.walk(preAst.callSignature);
walker.walk(preAst.block);
}
function walkObjectLiteralExpressionChildren(preAst: ObjectLiteralExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyAssignments);
}
function walkCastExpressionChildren(preAst: CastExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.type);
walker.walk(preAst.expression);
}
function walkParenthesizedExpressionChildren(preAst: ParenthesizedExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
}
function walkElementAccessExpressionChildren(preAst: ElementAccessExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
walker.walk(preAst.argumentExpression);
}
function walkMemberAccessExpressionChildren(preAst: MemberAccessExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
walker.walk(preAst.name);
}
function walkQualifiedNameChildren(preAst: QualifiedNameSyntax, walker: AstWalker): void {
walker.walk(preAst.left);
walker.walk(preAst.right);
}
function walkBinaryExpressionChildren(preAst: BinaryExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.left);
walker.walk(preAst.right);
}
function walkEqualsValueClauseChildren(preAst: EqualsValueClauseSyntax, walker: AstWalker): void {
walker.walk(preAst.value);
}
function walkTypeParameterChildren(preAst: TypeParameterSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.constraint);
}
function walkTypeParameterListChildren(preAst: TypeParameterListSyntax, walker: AstWalker): void {
walker.walk(preAst.typeParameters);
}
function walkGenericTypeChildren(preAst: GenericTypeSyntax, walker: AstWalker): void {
walker.walk(preAst.name);
walker.walk(preAst.typeArgumentList);
}
function walkTypeAnnotationChildren(preAst: TypeAnnotationSyntax, walker: AstWalker): void {
walker.walk(preAst.type);
}
function walkTypeQueryChildren(preAst: TypeQuerySyntax, walker: AstWalker): void {
walker.walk(preAst.name);
}
function walkInvocationExpressionChildren(preAst: InvocationExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
walker.walk(preAst.argumentList);
}
function walkObjectCreationExpressionChildren(preAst: ObjectCreationExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
walker.walk(preAst.argumentList);
}
function walkTrinaryExpressionChildren(preAst: ConditionalExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.condition);
walker.walk(preAst.whenTrue);
walker.walk(preAst.whenFalse);
}
function walkFunctionExpressionChildren(preAst: FunctionExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.callSignature);
walker.walk(preAst.block);
}
function walkFunctionTypeChildren(preAst: FunctionTypeSyntax, walker: AstWalker): void {
walker.walk(preAst.typeParameterList);
walker.walk(preAst.parameterList);
walker.walk(preAst.type);
}
function walkParenthesizedArrowFunctionExpressionChildren(preAst: ParenthesizedArrowFunctionExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.callSignature);
walker.walk(preAst.block);
walker.walk(preAst.expression);
}
function walkSimpleArrowFunctionExpressionChildren(preAst: SimpleArrowFunctionExpressionSyntax, walker: AstWalker): void {
walker.walk(preAst.parameter);
walker.walk(preAst.block);
walker.walk(preAst.expression);
}
function walkMemberFunctionDeclarationChildren(preAst: MemberFunctionDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyName);
walker.walk(preAst.callSignature);
walker.walk(preAst.block);
}
function walkFuncDeclChildren(preAst: FunctionDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.callSignature);
walker.walk(preAst.block);
}
function walkIndexMemberDeclarationChildren(preAst: IndexMemberDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.indexSignature);
}
function walkIndexSignatureChildren(preAst: IndexSignatureSyntax, walker: AstWalker): void {
walker.walk(preAst.parameters);
walker.walk(preAst.typeAnnotation);
}
function walkCallSignatureChildren(preAst: CallSignatureSyntax, walker: AstWalker): void {
walker.walk(preAst.typeParameterList);
walker.walk(preAst.parameterList);
walker.walk(preAst.typeAnnotation);
}
function walkConstraintChildren(preAst: ConstraintSyntax, walker: AstWalker): void {
walker.walk(preAst.typeOrExpression);
}
function walkConstructorDeclarationChildren(preAst: ConstructorDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.callSignature);
walker.walk(preAst.block);
}
function walkConstructorTypeChildren(preAst: FunctionTypeSyntax, walker: AstWalker): void {
walker.walk(preAst.typeParameterList);
walker.walk(preAst.parameterList);
walker.walk(preAst.type);
}
function walkConstructSignatureChildren(preAst: ConstructSignatureSyntax, walker: AstWalker): void {
walker.walk(preAst.callSignature);
}
function walkParameterChildren(preAst: ParameterSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.typeAnnotation);
walker.walk(preAst.equalsValueClause);
}
function walkParameterListChildren(preAst: ParameterListSyntax, walker: AstWalker): void {
walker.walk(preAst.parameters);
}
function walkPropertySignatureChildren(preAst: PropertySignatureSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyName);
walker.walk(preAst.typeAnnotation);
}
function walkVariableDeclaratorChildren(preAst: VariableDeclaratorSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyName);
walker.walk(preAst.typeAnnotation);
walker.walk(preAst.equalsValueClause);
}
function walkMemberVariableDeclarationChildren(preAst: MemberVariableDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.variableDeclarator);
}
function walkMethodSignatureChildren(preAst: MethodSignatureSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyName);
walker.walk(preAst.callSignature);
}
function walkReturnStatementChildren(preAst: ReturnStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
}
function walkForStatementChildren(preAst: ForStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.variableDeclaration);
walker.walk(preAst.initializer);
walker.walk(preAst.condition);
walker.walk(preAst.incrementor);
walker.walk(preAst.statement);
}
function walkForInStatementChildren(preAst: ForInStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.variableDeclaration);
walker.walk(preAst.left);
walker.walk(preAst.expression);
walker.walk(preAst.statement);
}
function walkIfStatementChildren(preAst: IfStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.condition);
walker.walk(preAst.statement);
walker.walk(preAst.elseClause);
}
function walkElseClauseChildren(preAst: ElseClauseSyntax, walker: AstWalker): void {
walker.walk(preAst.statement);
}
function walkWhileStatementChildren(preAst: WhileStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.condition);
walker.walk(preAst.statement);
}
function walkDoStatementChildren(preAst: DoStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.condition);
walker.walk(preAst.statement);
}
function walkBlockChildren(preAst: BlockSyntax, walker: AstWalker): void {
walker.walk(preAst.statements);
}
function walkVariableDeclarationChildren(preAst: VariableDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.variableDeclarators);
}
function walkCaseSwitchClauseChildren(preAst: CaseSwitchClauseSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
walker.walk(preAst.statements);
}
function walkDefaultSwitchClauseChildren(preAst: DefaultSwitchClauseSyntax, walker: AstWalker): void {
walker.walk(preAst.statements);
}
function walkSwitchStatementChildren(preAst: SwitchStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
walker.walk(preAst.switchClauses);
}
function walkTryStatementChildren(preAst: TryStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.block);
walker.walk(preAst.catchClause);
walker.walk(preAst.finallyClause);
}
function walkCatchClauseChildren(preAst: CatchClauseSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.typeAnnotation);
walker.walk(preAst.block);
}
function walkExternalModuleReferenceChildren(preAst: ExternalModuleReferenceSyntax, walker: AstWalker): void {
walker.walk(preAst.stringLiteral);
}
function walkFinallyClauseChildren(preAst: FinallyClauseSyntax, walker: AstWalker): void {
walker.walk(preAst.block);
}
function walkClassDeclChildren(preAst: ClassDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.typeParameterList);
walker.walk(preAst.heritageClauses);
walker.walk(preAst.classElements);
}
function walkScriptChildren(preAst: SourceUnitSyntax, walker: AstWalker): void {
walker.walk(preAst.moduleElements);
}
function walkHeritageClauseChildren(preAst: HeritageClauseSyntax, walker: AstWalker): void {
walker.walk(preAst.typeNames);
}
function walkInterfaceDeclerationChildren(preAst: InterfaceDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.typeParameterList);
walker.walk(preAst.heritageClauses);
walker.walk(preAst.body);
}
function walkObjectTypeChildren(preAst: ObjectTypeSyntax, walker: AstWalker): void {
walker.walk(preAst.typeMembers);
}
function walkArrayTypeChildren(preAst: ArrayTypeSyntax, walker: AstWalker): void {
walker.walk(preAst.type);
}
function walkModuleDeclarationChildren(preAst: ModuleDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.name);
walker.walk(preAst.stringLiteral);
walker.walk(preAst.moduleElements);
}
function walkModuleNameModuleReferenceChildren(preAst: ModuleNameModuleReferenceSyntax, walker: AstWalker): void {
walker.walk(preAst.moduleName);
}
function walkEnumDeclarationChildren(preAst: EnumDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.enumElements);
}
function walkEnumElementChildren(preAst: EnumElementSyntax, walker: AstWalker): void {
walker.walk(preAst.propertyName);
walker.walk(preAst.equalsValueClause);
}
function walkImportDeclarationChildren(preAst: ImportDeclarationSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.moduleReference);
}
function walkExportAssignmentChildren(preAst: ExportAssignmentSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
}
function walkWithStatementChildren(preAst: WithStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.condition);
walker.walk(preAst.statement);
}
function walkExpressionStatementChildren(preAst: ExpressionStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.expression);
}
function walkLabeledStatementChildren(preAst: LabeledStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.identifier);
walker.walk(preAst.statement);
}
function walkVariableStatementChildren(preAst: VariableStatementSyntax, walker: AstWalker): void {
walker.walk(preAst.variableDeclaration);
}
var childrenWalkers: IAstWalkChildren[] = new Array<IAstWalkChildren>(SyntaxKind.LastNode + 1);
// Tokens/trivia can't ever be walked into.
for (var i = SyntaxKind.FirstToken, n = SyntaxKind.LastToken; i <= n; i++) {
childrenWalkers[i] = null;
}
for (var i = SyntaxKind.FirstTrivia, n = SyntaxKind.LastTrivia; i <= n; i++) {
childrenWalkers[i] = null;
}
childrenWalkers[SyntaxKind.AddAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.AddExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.AndAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.AnyKeyword] = null;
childrenWalkers[SyntaxKind.ArgumentList] = walkArgumentListChildren;
childrenWalkers[SyntaxKind.ArrayLiteralExpression] = walkArrayLiteralExpressionChildren;
childrenWalkers[SyntaxKind.ArrayType] = walkArrayTypeChildren;
childrenWalkers[SyntaxKind.SimpleArrowFunctionExpression] = walkSimpleArrowFunctionExpressionChildren;
childrenWalkers[SyntaxKind.ParenthesizedArrowFunctionExpression] = walkParenthesizedArrowFunctionExpressionChildren;
childrenWalkers[SyntaxKind.AssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.BitwiseAndExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.BitwiseExclusiveOrExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.BitwiseNotExpression] = walkPrefixUnaryExpressionChildren;
childrenWalkers[SyntaxKind.BitwiseOrExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.Block] = walkBlockChildren;
childrenWalkers[SyntaxKind.BooleanKeyword] = null;
childrenWalkers[SyntaxKind.BreakStatement] = null;
childrenWalkers[SyntaxKind.CallSignature] = walkCallSignatureChildren;
childrenWalkers[SyntaxKind.CaseSwitchClause] = walkCaseSwitchClauseChildren;
childrenWalkers[SyntaxKind.CastExpression] = walkCastExpressionChildren;
childrenWalkers[SyntaxKind.CatchClause] = walkCatchClauseChildren;
childrenWalkers[SyntaxKind.ClassDeclaration] = walkClassDeclChildren;
childrenWalkers[SyntaxKind.CommaExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.ConditionalExpression] = walkTrinaryExpressionChildren;
childrenWalkers[SyntaxKind.Constraint] = walkConstraintChildren;
childrenWalkers[SyntaxKind.ConstructorDeclaration] = walkConstructorDeclarationChildren;
childrenWalkers[SyntaxKind.ConstructSignature] = walkConstructSignatureChildren;
childrenWalkers[SyntaxKind.ContinueStatement] = null;
childrenWalkers[SyntaxKind.ConstructorType] = walkConstructorTypeChildren;
childrenWalkers[SyntaxKind.DebuggerStatement] = null;
childrenWalkers[SyntaxKind.DefaultSwitchClause] = walkDefaultSwitchClauseChildren;
childrenWalkers[SyntaxKind.DeleteExpression] = walkDeleteExpressionChildren;
childrenWalkers[SyntaxKind.DivideAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.DivideExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.DoStatement] = walkDoStatementChildren;
childrenWalkers[SyntaxKind.ElementAccessExpression] = walkElementAccessExpressionChildren;
childrenWalkers[SyntaxKind.ElseClause] = walkElseClauseChildren;
childrenWalkers[SyntaxKind.EmptyStatement] = null;
childrenWalkers[SyntaxKind.EnumDeclaration] = walkEnumDeclarationChildren;
childrenWalkers[SyntaxKind.EnumElement] = walkEnumElementChildren;
childrenWalkers[SyntaxKind.EqualsExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.EqualsValueClause] = walkEqualsValueClauseChildren;
childrenWalkers[SyntaxKind.EqualsWithTypeConversionExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.ExclusiveOrAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.ExportAssignment] = walkExportAssignmentChildren;
childrenWalkers[SyntaxKind.ExpressionStatement] = walkExpressionStatementChildren;
childrenWalkers[SyntaxKind.ExtendsHeritageClause] = walkHeritageClauseChildren;
childrenWalkers[SyntaxKind.ExternalModuleReference] = walkExternalModuleReferenceChildren;
childrenWalkers[SyntaxKind.FalseKeyword] = null;
childrenWalkers[SyntaxKind.FinallyClause] = walkFinallyClauseChildren;
childrenWalkers[SyntaxKind.ForInStatement] = walkForInStatementChildren;
childrenWalkers[SyntaxKind.ForStatement] = walkForStatementChildren;
childrenWalkers[SyntaxKind.FunctionDeclaration] = walkFuncDeclChildren;
childrenWalkers[SyntaxKind.FunctionExpression] = walkFunctionExpressionChildren;
childrenWalkers[SyntaxKind.FunctionPropertyAssignment] = walkFunctionPropertyAssignmentChildren;
childrenWalkers[SyntaxKind.FunctionType] = walkFunctionTypeChildren;
childrenWalkers[SyntaxKind.GenericType] = walkGenericTypeChildren;
childrenWalkers[SyntaxKind.GetAccessor] = walkGetAccessorChildren;
childrenWalkers[SyntaxKind.GreaterThanExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.GreaterThanOrEqualExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.IfStatement] = walkIfStatementChildren;
childrenWalkers[SyntaxKind.ImplementsHeritageClause] = walkHeritageClauseChildren;
childrenWalkers[SyntaxKind.ImportDeclaration] = walkImportDeclarationChildren;
childrenWalkers[SyntaxKind.IndexMemberDeclaration] = walkIndexMemberDeclarationChildren;
childrenWalkers[SyntaxKind.IndexSignature] = walkIndexSignatureChildren;
childrenWalkers[SyntaxKind.InExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.InstanceOfExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.InterfaceDeclaration] = walkInterfaceDeclerationChildren;
childrenWalkers[SyntaxKind.InvocationExpression] = walkInvocationExpressionChildren;
childrenWalkers[SyntaxKind.LabeledStatement] = walkLabeledStatementChildren;
childrenWalkers[SyntaxKind.LeftShiftAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.LeftShiftExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.LessThanExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.LessThanOrEqualExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.List] = walkListChildren;
childrenWalkers[SyntaxKind.LogicalAndExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.LogicalNotExpression] = walkPrefixUnaryExpressionChildren;
childrenWalkers[SyntaxKind.LogicalOrExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.MemberAccessExpression] = walkMemberAccessExpressionChildren;
childrenWalkers[SyntaxKind.MemberFunctionDeclaration] = walkMemberFunctionDeclarationChildren;
childrenWalkers[SyntaxKind.MemberVariableDeclaration] = walkMemberVariableDeclarationChildren;
childrenWalkers[SyntaxKind.MethodSignature] = walkMethodSignatureChildren;
childrenWalkers[SyntaxKind.ModuleDeclaration] = walkModuleDeclarationChildren;
childrenWalkers[SyntaxKind.ModuleNameModuleReference] = walkModuleNameModuleReferenceChildren;
childrenWalkers[SyntaxKind.ModuloAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.ModuloExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.MultiplyAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.MultiplyExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.IdentifierName] = null;
childrenWalkers[SyntaxKind.NegateExpression] = walkPrefixUnaryExpressionChildren;
childrenWalkers[SyntaxKind.None] = null;
childrenWalkers[SyntaxKind.NotEqualsExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.NotEqualsWithTypeConversionExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.NullKeyword] = null;
childrenWalkers[SyntaxKind.NumberKeyword] = null;
childrenWalkers[SyntaxKind.NumericLiteral] = null;
childrenWalkers[SyntaxKind.ObjectCreationExpression] = walkObjectCreationExpressionChildren;
childrenWalkers[SyntaxKind.ObjectLiteralExpression] = walkObjectLiteralExpressionChildren;
childrenWalkers[SyntaxKind.ObjectType] = walkObjectTypeChildren;
childrenWalkers[SyntaxKind.OmittedExpression] = null;
childrenWalkers[SyntaxKind.OrAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.Parameter] = walkParameterChildren;
childrenWalkers[SyntaxKind.ParameterList] = walkParameterListChildren;
childrenWalkers[SyntaxKind.ParenthesizedExpression] = walkParenthesizedExpressionChildren;
childrenWalkers[SyntaxKind.PlusExpression] = walkPrefixUnaryExpressionChildren;
childrenWalkers[SyntaxKind.PostDecrementExpression] = walkPostfixUnaryExpressionChildren;
childrenWalkers[SyntaxKind.PostIncrementExpression] = walkPostfixUnaryExpressionChildren;
childrenWalkers[SyntaxKind.PreDecrementExpression] = walkPrefixUnaryExpressionChildren;
childrenWalkers[SyntaxKind.PreIncrementExpression] = walkPrefixUnaryExpressionChildren;
childrenWalkers[SyntaxKind.PropertySignature] = walkPropertySignatureChildren;
childrenWalkers[SyntaxKind.QualifiedName] = walkQualifiedNameChildren;
childrenWalkers[SyntaxKind.RegularExpressionLiteral] = null;
childrenWalkers[SyntaxKind.ReturnStatement] = walkReturnStatementChildren;
childrenWalkers[SyntaxKind.SourceUnit] = walkScriptChildren;
childrenWalkers[SyntaxKind.SeparatedList] = walkSeparatedListChildren;
childrenWalkers[SyntaxKind.SetAccessor] = walkSetAccessorChildren;
childrenWalkers[SyntaxKind.SignedRightShiftAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.SignedRightShiftExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.SimplePropertyAssignment] = walkSimplePropertyAssignmentChildren;
childrenWalkers[SyntaxKind.StringLiteral] = null;
childrenWalkers[SyntaxKind.StringKeyword] = null;
childrenWalkers[SyntaxKind.SubtractAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.SubtractExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.SuperKeyword] = null;
childrenWalkers[SyntaxKind.SwitchStatement] = walkSwitchStatementChildren;
childrenWalkers[SyntaxKind.ThisKeyword] = null;
childrenWalkers[SyntaxKind.ThrowStatement] = walkThrowStatementChildren;
childrenWalkers[SyntaxKind.TriviaList] = null;
childrenWalkers[SyntaxKind.TrueKeyword] = null;
childrenWalkers[SyntaxKind.TryStatement] = walkTryStatementChildren;
childrenWalkers[SyntaxKind.TypeAnnotation] = walkTypeAnnotationChildren;
childrenWalkers[SyntaxKind.TypeArgumentList] = walkTypeArgumentListChildren;
childrenWalkers[SyntaxKind.TypeOfExpression] = walkTypeOfExpressionChildren;
childrenWalkers[SyntaxKind.TypeParameter] = walkTypeParameterChildren;
childrenWalkers[SyntaxKind.TypeParameterList] = walkTypeParameterListChildren;
childrenWalkers[SyntaxKind.TypeQuery] = walkTypeQueryChildren;
childrenWalkers[SyntaxKind.UnsignedRightShiftAssignmentExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.UnsignedRightShiftExpression] = walkBinaryExpressionChildren;
childrenWalkers[SyntaxKind.VariableDeclaration] = walkVariableDeclarationChildren;
childrenWalkers[SyntaxKind.VariableDeclarator] = walkVariableDeclaratorChildren;
childrenWalkers[SyntaxKind.VariableStatement] = walkVariableStatementChildren;
childrenWalkers[SyntaxKind.VoidExpression] = walkVoidExpressionChildren;
childrenWalkers[SyntaxKind.VoidKeyword] = null;
childrenWalkers[SyntaxKind.WhileStatement] = walkWhileStatementChildren;
childrenWalkers[SyntaxKind.WithStatement] = walkWithStatementChildren;
// Verify the code is up to date with the enum
for (var e in SyntaxKind) {
if (SyntaxKind.hasOwnProperty(e) && StringUtilities.isString(SyntaxKind[e])) {
TypeScript.Debug.assert(childrenWalkers[e] !== undefined, "Fix initWalkers: " + SyntaxKind[e]);
}
}
export class AstWalkOptions {
public goChildren = true;
public stopWalking = false;
}
interface IAstWalkChildren {
(preAst: ISyntaxElement, walker: AstWalker): void;
}
export interface IAstWalker {
options: AstWalkOptions;
state: any
}
interface AstWalker {
walk(ast: ISyntaxElement): void;
}
class SimplePreAstWalker implements AstWalker {
public options: AstWalkOptions = new AstWalkOptions();
constructor(
private pre: (ast: ISyntaxElement, state: any) => void,
public state: any) {
}
public walk(ast: ISyntaxElement): void {
if (!ast) {
return;
}
this.pre(ast, this.state);
var walker = childrenWalkers[ast.kind()];
if (walker) {
walker(ast, this);
}
}
}
class SimplePrePostAstWalker implements AstWalker {
public options: AstWalkOptions = new AstWalkOptions();
constructor(
private pre: (ast: ISyntaxElement, state: any) => void,
private post: (ast: ISyntaxElement, state: any) => void,
public state: any) {
}
public walk(ast: ISyntaxElement): void {
if (!ast) {
return;
}
this.pre(ast, this.state);
var walker = childrenWalkers[ast.kind()];
if (walker) {
walker(ast, this);
}
this.post(ast, this.state);
}
}
class NormalAstWalker implements AstWalker {
public options: AstWalkOptions = new AstWalkOptions();
constructor(
private pre: (ast: ISyntaxElement, walker: IAstWalker) => void,
private post: (ast: ISyntaxElement, walker: IAstWalker) => void,
public state: any) {
}
public walk(ast: ISyntaxElement): void {
if (!ast) {
return;
}
// If we're stopping, then bail out immediately.
if (this.options.stopWalking) {
return;
}
this.pre(ast, this);
// If we were asked to stop, then stop.
if (this.options.stopWalking) {
return;
}
if (this.options.goChildren) {
// Call the "walkChildren" function corresponding to "nodeType".
var walker = childrenWalkers[ast.kind()];
if (walker) {
walker(ast, this);
}
}
else {
// no go only applies to children of node issuing it
this.options.goChildren = true;
}
if (this.post) {
this.post(ast, this);
}
}
}
export class AstWalkerFactory {
public walk(ast: ISyntaxElement, pre: (ast: ISyntaxElement, walker: IAstWalker) => void, post?: (ast: ISyntaxElement, walker: IAstWalker) => void, state?: any): void {
new NormalAstWalker(pre, post, state).walk(ast);
}
public simpleWalk(ast: ISyntaxElement, pre: (ast: ISyntaxElement, state: any) => void, post?: (ast: ISyntaxElement, state: any) => void, state?: any): void {
if (post) {
new SimplePrePostAstWalker(pre, post, state).walk(ast);
}
else {
new SimplePreAstWalker(pre, state).walk(ast);
}
}
}
var globalAstWalkerFactory = new AstWalkerFactory();
export function getAstWalkerFactory(): AstWalkerFactory {
return globalAstWalkerFactory;
}
}
+131
View File
@@ -0,0 +1,131 @@
///<reference path='..\core\integerUtilities.ts' />
module TypeScript {
export class BloomFilter {
private bitArray: boolean[];
private hashFunctionCount: number;
public static falsePositiveProbability: number = 0.0001;
/*
* From the bloom filter calculator here: http://hur.st/bloomfilter?n=4&p=1.0E-20
*
* 1) n = Number of items in the filter
*
* 2) p = Probability of false positives, (a double between 0 and 1).
*
* 3) m = Number of bits in the filter
*
* 4) k = Number of hash functions
*
* m = ceil((n * log(p)) / log(1.0 / (pow(2.0, log(2.0)))))
*
* k = round(log(2.0) * m / n)
*
*/
constructor(expectedCount: number) {
var m: number = Math.max(1, BloomFilter.computeM(expectedCount));
var k: number = Math.max(1, BloomFilter.computeK(expectedCount));;
// We must have size in even bytes, so that when we deserialize from bytes we get a bit array with the same count.
// The count is used by the hash functions.
var sizeInEvenBytes = (m + 7) & ~7;
this.bitArray = [];
for (var i = 0, len = sizeInEvenBytes; i < len; i++) {
this.bitArray[i] = false;
}
this.hashFunctionCount = k;
}
// m = ceil((n * log(p)) / log(1.0 / (pow(2.0, log(2.0)))))
static computeM(expectedCount: number): number {
var p: number = BloomFilter.falsePositiveProbability;
var n: number = expectedCount;
var numerator = n * Math.log(p);
var denominator = Math.log(1.0 / Math.pow(2.0, Math.log(2.0)));
return Math.ceil(numerator / denominator);
}
// k = round(log(2.0) * m / n)
static computeK(expectedCount: number): number {
var n: number = expectedCount;
var m: number = BloomFilter.computeM(expectedCount);
var temp = Math.log(2.0) * m / n;
return Math.round(temp);
}
/** Modification of the murmurhash2 algorithm. Code is simpler because it operates over
* strings instead of byte arrays. Because each string character is two bytes, it is known
* that the input will be an even number of bytes (though not necessarily a multiple of 4).
*
* This is needed over the normal 'string.GetHashCode()' because we need to be able to generate
* 'k' different well distributed hashes for any given string s. Also, we want to be able to
* generate these hashes without allocating any memory. My ideal solution would be to use an
* MD5 hash. However, there appears to be no way to do MD5 in .Net where you can:
*
* a) feed it individual values instead of a byte[]
*
* b) have the hash computed into a byte[] you provide instead of a newly allocated one
*
* Generating 'k' pieces of garbage on each insert and lookup seems very wasteful. So,
* instead, we use murmur hash since it provides well distributed values, allows for a
* seed, and allocates no memory.
*
* Murmur hash is public domain. Actual code is included below as reference.
*/
private computeHash(key: string, seed: number): number {
return Hash.computeMurmur2StringHashCode(key, seed);
}
public addKeys(keys: ts.Map<any>) {
for (var name in keys) {
if (ts.lookUp(keys, name)) {
this.add(name);
}
}
}
public add(value: string) {
for (var i = 0; i < this.hashFunctionCount; i++) {
var hash = this.computeHash(value, i);
hash = hash % this.bitArray.length;
this.bitArray[Math.abs(hash)] = true;
}
}
public probablyContains(value: string): boolean {
for (var i = 0; i < this.hashFunctionCount; i++) {
var hash = this.computeHash(value, i);
hash = hash % this.bitArray.length;
if (!this.bitArray[Math.abs(hash)]) {
return false;
}
}
return true;
}
public isEquivalent(filter: BloomFilter): boolean {
return BloomFilter.isEquivalent(this.bitArray, filter.bitArray)
&& this.hashFunctionCount === filter.hashFunctionCount;
}
static isEquivalent(array1: boolean[], array2: boolean[]): boolean {
if (array1.length !== array2.length) {
return false;
}
for (var i = 0; i < array1.length; i++) {
if (array1[i] !== array2[i]) {
return false;
}
}
return true;
}
}
}
File diff suppressed because it is too large Load Diff
+47
View File
@@ -0,0 +1,47 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='references.ts' />
module TypeScript {
export interface Logger {
information(): boolean;
debug(): boolean;
warning(): boolean;
error(): boolean;
fatal(): boolean;
log(s: string): void;
}
export class NullLogger implements Logger {
public information(): boolean { return false; }
public debug(): boolean { return false; }
public warning(): boolean { return false; }
public error(): boolean { return false; }
public fatal(): boolean { return false; }
public log(s: string): void {
}
}
export function timeFunction(logger: Logger, funcDescription: string, func: () => any): any {
var start = (new Date()).getTime();
var result = func();
var end = (new Date()).getTime();
if (logger.information()) {
logger.log(funcDescription + " completed in " + (end - start) + " msec");
}
return result;
}
}
File diff suppressed because it is too large Load Diff
+6
View File
@@ -0,0 +1,6 @@
declare class Enumerator {
public atEnd(): boolean;
public moveNext(): boolean;
public item(): any;
constructor (o: any);
}
+187
View File
@@ -0,0 +1,187 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='references.ts' />
module TypeScript {
var proto = "__proto__"
class BlockIntrinsics<T> {
public prototype: T = undefined;
public toString: T = undefined;
public toLocaleString: T = undefined;
public valueOf: T = undefined;
public hasOwnProperty: T = undefined;
public propertyIsEnumerable: T = undefined;
public isPrototypeOf: T = undefined;
[s: string]: T;
constructor() {
// initialize the 'constructor' field
this["constructor"] = undefined;
// First we set it to null, because that's the only way to erase the value in node. Then we set it to undefined in case we are not in node, since
// in StringHashTable below, we check for undefined explicitly.
this[proto] = null;
this[proto] = undefined;
}
}
export function createIntrinsicsObject<T>(): ts.Map<T> {
return new BlockIntrinsics<T>();
}
//export interface IHashTable<T> {
// getAllKeys(): string[];
// add(key: string, data: T): boolean;
// addOrUpdate(key: string, data: T): boolean;
// map(fn: (k: string, value: T, context: any) => void , context: any): void;
// every(fn: (k: string, value: T, context: any) => void , context: any): boolean;
// some(fn: (k: string, value: T, context: any) => void , context: any): boolean;
// count(): number;
// lookup(key: string): T;
//}
//export class StringHashTable<T> implements IHashTable<T> {
// private itemCount = 0;
// private table: IIndexable<T> = createIntrinsicsObject<T>();
// public getAllKeys(): string[] {
// var result: string[] = [];
// for (var k in this.table) {
// if (this.table[k] !== undefined) {
// result.push(k);
// }
// }
// return result;
// }
// public add(key: string, data: T): boolean {
// if (this.table[key] !== undefined) {
// return false;
// }
// this.table[key] = data;
// this.itemCount++;
// return true;
// }
// public addOrUpdate(key: string, data: T): boolean {
// if (this.table[key] !== undefined) {
// this.table[key] = data;
// return false;
// }
// this.table[key] = data;
// this.itemCount++;
// return true;
// }
// public map(fn: (k: string, value: T, context: any) => void , context: any) {
// for (var k in this.table) {
// var data = this.table[k];
// if (data !== undefined) {
// fn(k, this.table[k], context);
// }
// }
// }
// public every(fn: (k: string, value: T, context: any) => void , context: any) {
// for (var k in this.table) {
// var data = this.table[k];
// if (data !== undefined) {
// if (!fn(k, this.table[k], context)) {
// return false;
// }
// }
// }
// return true;
// }
// public some(fn: (k: string, value: T, context: any) => void , context: any) {
// for (var k in this.table) {
// var data = this.table[k];
// if (data !== undefined) {
// if (fn(k, this.table[k], context)) {
// return true;
// }
// }
// }
// return false;
// }
// public count(): number {
// return this.itemCount;
// }
// public lookup(key: string) : T {
// var data = this.table[key];
// return data === undefined ? null : data;
// }
// public remove(key: string): void {
// if (this.table[key] !== undefined) {
// this.table[key] = undefined;
// this.itemCount--;
// }
// }
//}
//export class IdentiferNameHashTable<T> extends StringHashTable<T> {
// public getAllKeys(): string[]{
// var result: string[] = [];
// super.map((k, v, c) => {
// if (v !== undefined) {
// result.push(k.substring(1));
// }
// }, null);
// return result;
// }
// public add(key: string, data: T): boolean {
// return super.add("#" + key, data);
// }
// public addOrUpdate(key: string, data: T): boolean {
// return super.addOrUpdate("#" + key, data);
// }
// public map(fn: (k: string, value: T, context: any) => void , context: any) {
// return super.map((k, v, c) => fn(k.substring(1), v, c), context);
// }
// public every(fn: (k: string, value: T, context: any) => void , context: any) {
// return super.every((k, v, c) => fn(k.substring(1), v, c), context);
// }
// public some(fn: (k: string, value: any, context: any) => void , context: any) {
// return super.some((k, v, c) => fn(k.substring(1), v, c), context);
// }
// public lookup(key: string): T {
// return super.lookup("#" + key);
// }
//}
}
+11
View File
@@ -0,0 +1,11 @@
module TypeScript {
export class IdentifierWalker extends SyntaxWalker {
constructor(public list: IIndexable<boolean>) {
super();
}
public visitToken(token: ISyntaxToken): void {
this.list[token.text()] = true;
}
}
}
+64
View File
@@ -0,0 +1,64 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='enumerator.ts' />
///<reference path='process.ts' />
///<reference path='core\references.ts' />
module TypeScript {
export interface IFindFileResult {
fileInformation: FileInformation;
path: string;
}
export module IOUtils {
// Creates the directory including its parent if not already present
function createDirectoryStructure(ioHost: IEnvironment, dirName: string) {
if (ioHost.directoryExists(dirName)) {
return;
}
var parentDirectory = ioHost.directoryName(dirName);
if (parentDirectory != "") {
createDirectoryStructure(ioHost, parentDirectory);
}
ioHost.createDirectory(dirName);
}
// Creates a file including its directory structure if not already present
export function writeFileAndFolderStructure(ioHost: IEnvironment, fileName: string, contents: string, writeByteOrderMark: boolean): void {
var start = new Date().getTime();
var path = ioHost.absolutePath(fileName);
TypeScript.ioHostResolvePathTime += new Date().getTime() - start;
var start = new Date().getTime();
var dirName = ioHost.directoryName(path);
TypeScript.ioHostDirectoryNameTime += new Date().getTime() - start;
var start = new Date().getTime();
createDirectoryStructure(ioHost, dirName);
TypeScript.ioHostCreateDirectoryStructureTime += new Date().getTime() - start;
var start = new Date().getTime();
ioHost.writeFile(path, contents, writeByteOrderMark);
TypeScript.ioHostWriteFileTime += new Date().getTime() - start;
}
export function combine(prefix: string, suffix: string): string {
return prefix + "/" + suffix;
}
}
}
+266
View File
@@ -0,0 +1,266 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path="references.ts" />
module TypeScript {
export interface IOptions {
name?: string;
flag?: boolean;
short?: string;
usage?: {
locCode: string; // DiagnosticCode
args: string[]
};
set?: (s: string) => void;
type?: string; // DiagnosticCode
experimental?: boolean;
}
export class OptionsParser {
private DEFAULT_SHORT_FLAG = "-";
private DEFAULT_LONG_FLAG = "--";
private printedVersion: boolean = false;
// Find the option record for the given string. Returns null if not found.
private findOption(arg: string) {
var upperCaseArg = arg && arg.toUpperCase();
for (var i = 0; i < this.options.length; i++) {
var current = this.options[i];
if (upperCaseArg === (current.short && current.short.toUpperCase()) ||
upperCaseArg === (current.name && current.name.toUpperCase())) {
return current;
}
}
return null;
}
public unnamed: string[] = [];
public options: IOptions[] = [];
constructor(public host: IEnvironment, public version: string) {
}
public printUsage() {
this.printVersion();
var optionsWord = getLocalizedText(DiagnosticCode.options, null);
var fileWord = getLocalizedText(DiagnosticCode.file1, null);
var tscSyntax = "tsc [" + optionsWord + "] [" + fileWord + " ..]";
var syntaxHelp = getLocalizedText(DiagnosticCode.Syntax_0, [tscSyntax]);
this.host.standardOut.WriteLine(syntaxHelp);
this.host.standardOut.WriteLine("");
this.host.standardOut.WriteLine(getLocalizedText(DiagnosticCode.Examples, null) + " tsc hello.ts");
this.host.standardOut.WriteLine(" tsc --out foo.js foo.ts");
this.host.standardOut.WriteLine(" tsc @args.txt");
this.host.standardOut.WriteLine("");
this.host.standardOut.WriteLine(getLocalizedText(DiagnosticCode.Options, null));
var output: string[][] = [];
var maxLength = 0;
var i = 0;
this.options = this.options.sort(function (a, b) {
var aName = a.name.toLowerCase();
var bName = b.name.toLowerCase();
if (aName > bName) {
return 1;
} else if (aName < bName) {
return -1;
} else {
return 0;
}
});
// Build up output array
for (i = 0; i < this.options.length; i++) {
var option = this.options[i];
if (option.experimental) {
continue;
}
if (!option.usage) {
break;
}
var usageString = " ";
var type = option.type ? (" " + TypeScript.getLocalizedText(option.type, null)) : "";
if (option.short) {
usageString += this.DEFAULT_SHORT_FLAG + option.short + type + ", ";
}
usageString += this.DEFAULT_LONG_FLAG + option.name + type;
output.push([usageString, TypeScript.getLocalizedText(option.usage.locCode, option.usage.args)]);
if (usageString.length > maxLength) {
maxLength = usageString.length;
}
}
var fileDescription = getLocalizedText(DiagnosticCode.Insert_command_line_options_and_files_from_a_file, null);
output.push([" @<" + fileWord + ">", fileDescription]);
// Print padded output
for (i = 0; i < output.length; i++) {
this.host.standardOut.WriteLine(output[i][0] + (new Array(maxLength - output[i][0].length + 3)).join(" ") + output[i][1]);
}
}
public printVersion() {
if (!this.printedVersion) {
this.host.standardOut.WriteLine(getLocalizedText(DiagnosticCode.Version_0, [this.version]));
this.printedVersion = true;
}
}
public option(name: string, config: IOptions, short?: string) {
if (!config) {
config = <any>short;
short = null;
}
config.name = name;
config.short = short;
config.flag = false;
this.options.push(config);
}
public flag(name: string, config: IOptions, short?: string) {
if (!config) {
config = <any>short;
short = null;
}
config.name = name;
config.short = short;
config.flag = true
this.options.push(config);
}
// Parse an arguments string
public parseString(argString: string) {
var position = 0;
var tokens = argString.match(/\s+|"|[^\s"]+/g);
function peek() {
return tokens[position];
}
function consume() {
return tokens[position++];
}
function consumeQuotedString() {
var value = '';
consume(); // skip opening quote.
var token = peek();
while (token && token !== '"') {
consume();
value += token;
token = peek();
}
consume(); // skip ending quote;
return value;
}
var args: string[] = [];
var currentArg = '';
while (position < tokens.length) {
var token = peek();
if (token === '"') {
currentArg += consumeQuotedString();
} else if (token.match(/\s/)) {
if (currentArg.length > 0) {
args.push(currentArg);
currentArg = '';
}
consume();
} else {
consume();
currentArg += token;
}
}
if (currentArg.length > 0) {
args.push(currentArg);
}
this.parse(args);
}
// Parse arguments as they come from the platform: split into arguments.
public parse(args: string[]) {
var position = 0;
function consume() {
return args[position++];
}
while (position < args.length) {
var current = consume();
var match = current.match(/^(--?|@)(.*)/);
var value: any = null;
if (match) {
if (match[1] === '@') {
this.parseString(this.host.readFile(match[2], null).contents);
} else {
var arg = match[2];
var option = this.findOption(arg);
if (option === null) {
this.host.standardOut.WriteLine(getDiagnosticMessage(DiagnosticCode.Unknown_compiler_option_0, [arg]));
this.host.standardOut.WriteLine(getLocalizedText(DiagnosticCode.Use_the_0_flag_to_see_options, ["--help"]));
} else {
if (!option.flag) {
value = consume();
if (value === undefined) {
// No value provided
this.host.standardOut.WriteLine(getDiagnosticMessage(DiagnosticCode.Option_0_specified_without_1, [arg, getLocalizedText(option.type, null)]));
this.host.standardOut.WriteLine(getLocalizedText(DiagnosticCode.Use_the_0_flag_to_see_options, ["--help"]));
continue;
}
}
option.set(value);
}
}
} else {
this.unnamed.push(current);
}
}
}
}
}
+193
View File
@@ -0,0 +1,193 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='references.ts' />
module TypeScript {
export function stripStartAndEndQuotes(str: string) {
var firstCharCode = str && str.charCodeAt(0);
if (str && str.length >= 2 && firstCharCode === str.charCodeAt(str.length - 1) && (firstCharCode === CharacterCodes.singleQuote || firstCharCode === CharacterCodes.doubleQuote)) {
return str.substring(1, str.length - 1);
}
return str;
}
export function isSingleQuoted(str: string) {
return str && str.length >= 2 && str.charCodeAt(0) === str.charCodeAt(str.length - 1) && str.charCodeAt(0) === CharacterCodes.singleQuote;
}
export function isDoubleQuoted(str: string) {
return str && str.length >= 2 && str.charCodeAt(0) === str.charCodeAt(str.length - 1) && str.charCodeAt(0) === CharacterCodes.doubleQuote;
}
export function isQuoted(str: string) {
return isDoubleQuoted(str) || isSingleQuoted(str);
}
export function quoteStr(str: string) {
return "\"" + str + "\"";
}
var switchToForwardSlashesRegEx = /\\/g;
export function switchToForwardSlashes(path: string) {
return path.replace(switchToForwardSlashesRegEx, "/");
}
export function trimModName(modName: string) {
// in case's it's a declare file...
if (modName.length > 5 && modName.substring(modName.length - 5, modName.length) === ".d.ts") {
return modName.substring(0, modName.length - 5);
}
if (modName.length > 3 && modName.substring(modName.length - 3, modName.length) === ".ts") {
return modName.substring(0, modName.length - 3);
}
// in case's it's a .js file
if (modName.length > 3 && modName.substring(modName.length - 3, modName.length) === ".js") {
return modName.substring(0, modName.length - 3);
}
return modName;
}
export function getDeclareFilePath(fname: string) {
return isTSFile(fname) ? changePathToDTS(fname) : changePathToDTS(fname);
}
function isFileOfExtension(fname: string, ext: string) {
var invariantFname = fname.toLocaleUpperCase();
var invariantExt = ext.toLocaleUpperCase();
var extLength = invariantExt.length;
return invariantFname.length > extLength && invariantFname.substring(invariantFname.length - extLength, invariantFname.length) === invariantExt;
}
export function isTSFile(fname: string) {
return isFileOfExtension(fname, ".ts");
}
export function isDTSFile(fname: string) {
return isFileOfExtension(fname, ".d.ts");
}
export function getPrettyName(modPath: string, quote=true, treatAsFileName=false): any {
var modName = treatAsFileName ? switchToForwardSlashes(modPath) : trimModName(stripStartAndEndQuotes(modPath));
var components = this.getPathComponents(modName);
return components.length ? (quote ? quoteStr(components[components.length - 1]) : components[components.length - 1]) : modPath;
}
export function getPathComponents(path: string) {
return path.split("/");
}
export function getRelativePathToFixedPath(fixedModFilePath: string, absoluteModPath: string, isAbsoultePathURL = true) {
absoluteModPath = switchToForwardSlashes(absoluteModPath);
var modComponents = this.getPathComponents(absoluteModPath);
var fixedModComponents = this.getPathComponents(fixedModFilePath);
// Find the component that differs
var joinStartIndex = 0;
for (; joinStartIndex < modComponents.length && joinStartIndex < fixedModComponents.length ; joinStartIndex++) {
if (fixedModComponents[joinStartIndex] !== modComponents[joinStartIndex]) {
break;
}
}
// Get the relative path
if (joinStartIndex !== 0) {
var relativePath = "";
var relativePathComponents = modComponents.slice(joinStartIndex, modComponents.length);
for (; joinStartIndex < fixedModComponents.length; joinStartIndex++) {
if (fixedModComponents[joinStartIndex] !== "") {
relativePath = relativePath + "../";
}
}
return relativePath + relativePathComponents.join("/");
}
if (isAbsoultePathURL && absoluteModPath.indexOf("://") === -1) {
absoluteModPath = "file:///" + absoluteModPath;
}
return absoluteModPath;
}
export function changePathToDTS(modPath: string) {
return trimModName(stripStartAndEndQuotes(modPath)) + ".d.ts";
}
export function isRelative(path: string) {
return path.length > 0 && path.charAt(0) === ".";
}
export function isRooted(path: string) {
return path.length > 0 && (path.charAt(0) === "\\" || path.charAt(0) === "/" || (path.indexOf(":\\") !== -1) || (path.indexOf(":/") !== -1));
}
export function getRootFilePath(outFname: string) {
if (outFname === "") {
return outFname;
}
else {
var isPath = outFname.indexOf("/") !== -1;
return isPath ? filePath(outFname) : "";
}
}
export function filePathComponents(fullPath: string) {
fullPath = switchToForwardSlashes(fullPath);
var components = getPathComponents(fullPath);
return components.slice(0, components.length - 1);
}
export function filePath(fullPath: string) {
var path = filePathComponents(fullPath);
return path.join("/") + "/";
}
export function convertToDirectoryPath(dirPath: string) {
if (dirPath && dirPath.charAt(dirPath.length - 1) !== "/") {
dirPath += "/";
}
return dirPath;
}
var normalizePathRegEx = /^\\\\[^\\]/;
export function normalizePath(path: string): string {
// If it's a UNC style path (i.e. \\server\share), convert to a URI style (i.e. file://server/share)
if (normalizePathRegEx.test(path)) {
path = "file:" + path;
}
var parts = this.getPathComponents(switchToForwardSlashes(path));
var normalizedParts: string[] = [];
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
if (part === ".") {
continue;
}
if (normalizedParts.length > 0 && ArrayUtilities.last(normalizedParts) !== ".." && part === "..") {
normalizedParts.pop();
continue;
}
normalizedParts.push(part);
}
return normalizedParts.join("/");
}
}
+208
View File
@@ -0,0 +1,208 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
module TypeScript {
export interface ILineAndCharacter {
line: number;
character: number;
}
// Note: This is being using by the host (VS) and is marshaled back and forth. When changing this make sure the changes
// are reflected in the managed side as well.
export interface IFileReference extends ILineAndCharacter {
path: string;
isResident: boolean;
position: number;
length: number;
}
///
/// Preprocessing
///
export interface IPreProcessedFileInfo {
referencedFiles: IFileReference[];
importedFiles: IFileReference[];
diagnostics: Diagnostic[];
isLibFile: boolean;
}
interface ITripleSlashDirectiveProperties {
noDefaultLib: boolean;
diagnostics: Diagnostic[];
referencedFiles: IFileReference[];
}
function isNoDefaultLibMatch(comment: string): RegExpExecArray {
var isNoDefaultLibRegex = /^(\/\/\/\s*<reference\s+no-default-lib=)('|")(.+?)\2\s*\/>/gim;
return isNoDefaultLibRegex.exec(comment);
}
export var tripleSlashReferenceRegExp = /^(\/\/\/\s*<reference\s+path=)('|")(.+?)\2\s*(static=('|")(.+?)\2\s*)*\/>/;
function getFileReferenceFromReferencePath(fileName: string, text: ISimpleText, position: number, comment: string, diagnostics: Diagnostic[]): IFileReference {
// First, just see if they've written: /// <reference\s+
// If so, then we'll consider this a reference directive and we'll report errors if it's
// malformed. Otherwise, we'll completely ignore this.
var lineMap = text.lineMap();
var simpleReferenceRegEx = /^\/\/\/\s*<reference\s+/gim;
if (simpleReferenceRegEx.exec(comment)) {
var isNoDefaultLib = isNoDefaultLibMatch(comment);
if (!isNoDefaultLib) {
var fullReferenceRegEx = tripleSlashReferenceRegExp;
var fullReference = fullReferenceRegEx.exec(comment);
if (!fullReference) {
// It matched the start of a reference directive, but wasn't well formed. Report
// an appropriate error to the user.
diagnostics.push(new Diagnostic(fileName, lineMap, position, comment.length, DiagnosticCode.Invalid_reference_directive_syntax));
}
else {
var path: string = normalizePath(fullReference[3]);
var adjustedPath = normalizePath(path);
var isResident = fullReference.length >= 7 && fullReference[6] === "true";
return {
line: 0,
character: 0,
position: 0,
length: 0,
path: switchToForwardSlashes(adjustedPath),
isResident: isResident
};
}
}
}
return null;
}
var reportDiagnostic = () => { };
function processImports(text: ISimpleText, scanner: Scanner.IScanner, token: ISyntaxToken, importedFiles: IFileReference[]): void {
var lineChar = { line: -1, character: -1 };
var lineMap = text.lineMap();
var start = new Date().getTime();
// Look for:
// import foo = module("foo")
while (token.kind() !== SyntaxKind.EndOfFileToken) {
if (token.kind() === SyntaxKind.ImportKeyword) {
var importToken = token;
token = scanner.scan(/*allowRegularExpression:*/ false);
if (SyntaxFacts.isIdentifierNameOrAnyKeyword(token)) {
token = scanner.scan(/*allowRegularExpression:*/ false);
if (token.kind() === SyntaxKind.EqualsToken) {
token = scanner.scan(/*allowRegularExpression:*/ false);
if (token.kind() === SyntaxKind.ModuleKeyword || token.kind() === SyntaxKind.RequireKeyword) {
token = scanner.scan(/*allowRegularExpression:*/ false);
if (token.kind() === SyntaxKind.OpenParenToken) {
token = scanner.scan(/*allowRegularExpression:*/ false);
lineMap.fillLineAndCharacterFromPosition(TypeScript.start(importToken, text), lineChar);
if (token.kind() === SyntaxKind.StringLiteral) {
var ref = {
line: lineChar.line,
character: lineChar.character,
position: TypeScript.start(token, text),
length: width(token),
path: stripStartAndEndQuotes(switchToForwardSlashes(token.text())),
isResident: false
};
importedFiles.push(ref);
}
}
}
}
}
}
token = scanner.scan(/*allowRegularExpression:*/ false);
}
var totalTime = new Date().getTime() - start;
//TypeScript.fileResolutionScanImportsTime += totalTime;
}
function processTripleSlashDirectives(fileName: string, text: ISimpleText, firstToken: ISyntaxToken): ITripleSlashDirectiveProperties {
var leadingTrivia = firstToken.leadingTrivia(text);
var position = 0;
var lineChar = { line: -1, character: -1 };
var noDefaultLib = false;
var diagnostics: Diagnostic[] = [];
var referencedFiles: IFileReference[] = [];
var lineMap = text.lineMap()
for (var i = 0, n = leadingTrivia.count(); i < n; i++) {
var trivia = leadingTrivia.syntaxTriviaAt(i);
if (trivia.kind() === SyntaxKind.SingleLineCommentTrivia) {
var triviaText = trivia.fullText();
var referencedCode = getFileReferenceFromReferencePath(fileName, text, position, triviaText, diagnostics);
if (referencedCode) {
lineMap.fillLineAndCharacterFromPosition(position, lineChar);
referencedCode.position = position;
referencedCode.length = trivia.fullWidth();
referencedCode.line = lineChar.line;
referencedCode.character = lineChar.character;
referencedFiles.push(referencedCode);
}
// is it a lib file?
var isNoDefaultLib = isNoDefaultLibMatch(triviaText);
if (isNoDefaultLib) {
noDefaultLib = isNoDefaultLib[3] === "true";
}
}
position += trivia.fullWidth();
}
return { noDefaultLib: noDefaultLib, diagnostics: diagnostics, referencedFiles: referencedFiles };
}
export function preProcessFile(fileName: string, sourceText: IScriptSnapshot, readImportFiles = true): IPreProcessedFileInfo {
var text = SimpleText.fromScriptSnapshot(sourceText);
var scanner = Scanner.createScanner(ts.ScriptTarget.ES5, text, reportDiagnostic);
var firstToken = scanner.scan(/*allowRegularExpression:*/ false);
// only search out dynamic mods
// if you find a dynamic mod, ignore every other mod inside, until you balance rcurlies
// var position
var importedFiles: IFileReference[] = [];
if (readImportFiles) {
processImports(text, scanner, firstToken, importedFiles);
}
var properties = processTripleSlashDirectives(fileName, text, firstToken);
return { referencedFiles: properties.referencedFiles, importedFiles: importedFiles, isLibFile: properties.noDefaultLib, diagnostics: properties.diagnostics };
}
export function getReferencedFiles(fileName: string, sourceText: IScriptSnapshot): IFileReference[] {
return preProcessFile(fileName, sourceText, false).referencedFiles;
}
} // Tools
+17
View File
@@ -0,0 +1,17 @@
//declare module process {
// export var argv: string[];
// export var platform: string;
// export function on(event: string, handler: (arg: any) => void ): void;
// export module stdout {
// export function write(str: string): any;
// export function on(event: string, action: () => void ): void;
// }
// export module stderr {
// export function write(str: string): any;
// export function on(event: string, action: () => void): void;
// }
// export module mainModule {
// export var filename: string;
// }
// export function exit(exitCode?: number): any;
//}
+37
View File
@@ -0,0 +1,37 @@
/////<reference path='resources\references.ts' />
/////<reference path='core\references.ts' />
/////<reference path='text\references.ts' />
/////<reference path='syntax\references.ts' />
/////<reference path='diagnostics.ts' />
/////<reference path='document.ts' />
/////<reference path='flags.ts' />
/////<reference path='hashTable.ts' />
/////<reference path='ast.ts' />
/////<reference path='astHelpers.ts' />
/////<reference path='astWalker.ts' />
/////<reference path='base64.ts' />
/////<reference path='sourceMapping.ts' />
/////<reference path='emitter.ts' />
/////<reference path='types.ts' />
/////<reference path='pathUtils.ts' />
/////<reference path='referenceResolution.ts' />
/////<reference path='precompile.ts' />
/////<reference path='referenceResolver.ts' />
/////<reference path='declarationEmitter.ts' />
/////<reference path='bloomFilter.ts' />
/////<reference path='identifierWalker.ts' />
/////<reference path='settings.ts' />
/////<reference path='typecheck\pullFlags.ts' />
/////<reference path='typecheck\pullDecls.ts' />
/////<reference path='typecheck\pullSymbols.ts' />
/////<reference path='typecheck\pullTypeEnclosingTypeWalker.ts' />
/////<reference path='typecheck\pullTypeResolutionContext.ts' />
/////<reference path='typecheck\pullTypeResolution.ts' />
/////<reference path='typecheck\pullSemanticInfo.ts' />
/////<reference path='typecheck\pullDeclCollection.ts' />
/////<reference path='typecheck\pullSymbolBinder.ts' />
/////<reference path='typecheck\pullHelpers.ts' />
/////<reference path='typecheck\pullInstantiationHelpers.ts' />
/////<reference path='typecheck\pullTypeInstantiation.ts' />
/////<reference path='typescript.ts' />
+270
View File
@@ -0,0 +1,270 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='references.ts' />
module TypeScript {
export class SourceMapPosition {
public sourceLine: number;
public sourceColumn: number;
public emittedLine: number;
public emittedColumn: number;
}
export class SourceMapping {
public start = new SourceMapPosition();
public end = new SourceMapPosition();
public nameIndex: number = -1;
public childMappings: SourceMapping[] = [];
}
export class SourceMapEntry {
constructor(
public emittedFile: string,
public emittedLine: number,
public emittedColumn: number,
public sourceFile: string,
public sourceLine: number,
public sourceColumn: number,
public sourceName: string) {
Debug.assert(isFinite(emittedLine));
Debug.assert(isFinite(emittedColumn));
Debug.assert(isFinite(sourceColumn));
Debug.assert(isFinite(sourceLine));
}
}
export class SourceMapper {
static MapFileExtension = ".map";
private jsFileName: string;
private sourceMapPath: string;
private sourceMapDirectory: string;
private sourceRoot: string;
public names: string[] = [];
private mappingLevel: ISpan[] = [];
// Below two arrays represent the information about sourceFile at that index.
private tsFilePaths: string[] = [];
private allSourceMappings: SourceMapping[][] = [];
public currentMappings: SourceMapping[][];
public currentNameIndex: number[];
private sourceMapEntries: SourceMapEntry[] = [];
constructor(private jsFile: TextWriter,
private sourceMapOut: TextWriter,
document: Document,
jsFilePath: string,
emitOptions: EmitOptions,
resolvePath: (path: string) => string) {
this.setSourceMapOptions(document, jsFilePath, emitOptions, resolvePath);
this.setNewSourceFile(document, emitOptions);
}
public getOutputFile(): OutputFile {
var result = this.sourceMapOut.getOutputFile();
result.sourceMapEntries = this.sourceMapEntries;
return result;
}
public increaseMappingLevel(ast: ISpan) {
this.mappingLevel.push(ast);
}
public decreaseMappingLevel(ast: any) {
Debug.assert(this.mappingLevel.length > 0, "Mapping level should never be less than 0. This suggests a missing start call.");
var expectedAst = this.mappingLevel.pop();
if (ast !== expectedAst) {
var expectedAstInfo: any = (<any>expectedAst).kind ? SyntaxKind[(<any>expectedAst).kind] : [expectedAst.start(), expectedAst.end()];
var astInfo: any = (<any>ast).kind ? SyntaxKind[(<any>ast).kind] : [ast.start(), ast.end()]
Debug.fail(
"Provided ast is not the expected ISyntaxElement, Expected: " + expectedAstInfo + " Given: " + astInfo)
}
}
public setNewSourceFile(document: Document, emitOptions: EmitOptions) {
// Set new mappings
var sourceMappings: SourceMapping[] = [];
this.allSourceMappings.push(sourceMappings);
this.currentMappings = [sourceMappings];
this.currentNameIndex = [];
// Set new source file path
this.setNewSourceFilePath(document, emitOptions);
}
private setSourceMapOptions(document: Document, jsFilePath: string, emitOptions: EmitOptions, resolvePath: (path: string) => string) {
// Decode mapRoot and sourceRoot
// Js File Name = pretty name of js file
var prettyJsFileName = TypeScript.getPrettyName(jsFilePath, false, true);
var prettyMapFileName = prettyJsFileName + SourceMapper.MapFileExtension;
this.jsFileName = prettyJsFileName;
// Figure out sourceMapPath and sourceMapDirectory
if (emitOptions.sourceMapRootDirectory()) {
// Get the sourceMap Directory
this.sourceMapDirectory = emitOptions.sourceMapRootDirectory();
if (document.emitToOwnOutputFile()) {
// 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
this.sourceMapDirectory = this.sourceMapDirectory + switchToForwardSlashes(getRootFilePath((document.fileName)).replace(emitOptions.commonDirectoryPath(), ""));
}
if (isRelative(this.sourceMapDirectory)) {
// The relative paths are relative to the common directory
this.sourceMapDirectory = emitOptions.commonDirectoryPath() + this.sourceMapDirectory;
this.sourceMapDirectory = convertToDirectoryPath(switchToForwardSlashes(resolvePath(this.sourceMapDirectory)));
this.sourceMapPath = getRelativePathToFixedPath(getRootFilePath(jsFilePath), this.sourceMapDirectory + prettyMapFileName);
}
else {
this.sourceMapPath = this.sourceMapDirectory + prettyMapFileName;
}
}
else {
this.sourceMapPath = prettyMapFileName;
this.sourceMapDirectory = getRootFilePath(jsFilePath);
}
this.sourceRoot = emitOptions.sourceRootDirectory();
}
private setNewSourceFilePath(document: Document, emitOptions: EmitOptions) {
var tsFilePath = switchToForwardSlashes(document.fileName);
if (emitOptions.sourceRootDirectory()) {
// Use the relative path corresponding to the common directory path
tsFilePath = getRelativePathToFixedPath(emitOptions.commonDirectoryPath(), tsFilePath);
}
else {
// Source locations relative to map file location
tsFilePath = getRelativePathToFixedPath(this.sourceMapDirectory, tsFilePath);
}
this.tsFilePaths.push(tsFilePath);
}
// Generate source mapping.
// Creating files can cause exceptions, they will be caught higher up in TypeScriptCompiler.emit
public emitSourceMapping(): void {
Debug.assert(
this.mappingLevel.length === 0,
"Mapping level is not 0. This suggest a missing end call. Value: " +
this.mappingLevel.map(item => ['Node of type', SyntaxKind[(<any>item).kind], 'at', item.start(), 'to', item.end()].join(' ')).join(', '));
// Output map file name into the js file
this.jsFile.WriteLine("//# sourceMappingURL=" + this.sourceMapPath);
// Now output map file
var mappingsString = "";
var prevEmittedColumn = 0;
var prevEmittedLine = 0;
var prevSourceColumn = 0;
var prevSourceLine = 0;
var prevSourceIndex = 0;
var prevNameIndex = 0;
var emitComma = false;
var recordedPosition: SourceMapPosition = null;
for (var sourceIndex = 0; sourceIndex < this.tsFilePaths.length; sourceIndex++) {
var recordSourceMapping = (mappedPosition: SourceMapPosition, nameIndex: number) => {
if (recordedPosition !== null &&
recordedPosition.emittedColumn === mappedPosition.emittedColumn &&
recordedPosition.emittedLine === mappedPosition.emittedLine) {
// This position is already recorded
return;
}
// Record this position
if (prevEmittedLine !== mappedPosition.emittedLine) {
while (prevEmittedLine < mappedPosition.emittedLine) {
prevEmittedColumn = 0;
mappingsString = mappingsString + ";";
prevEmittedLine++;
}
emitComma = false;
}
else if (emitComma) {
mappingsString = mappingsString + ",";
}
this.sourceMapEntries.push(new SourceMapEntry(
this.jsFileName,
mappedPosition.emittedLine + 1,
mappedPosition.emittedColumn + 1,
this.tsFilePaths[sourceIndex],
mappedPosition.sourceLine,
mappedPosition.sourceColumn + 1,
nameIndex >= 0 ? this.names[nameIndex] : undefined));
// 1. Relative Column
mappingsString = mappingsString + Base64VLQFormat.encode(mappedPosition.emittedColumn - prevEmittedColumn);
prevEmittedColumn = mappedPosition.emittedColumn;
// 2. Relative sourceIndex
mappingsString = mappingsString + Base64VLQFormat.encode(sourceIndex - prevSourceIndex);
prevSourceIndex = sourceIndex;
// 3. Relative sourceLine 0 based
mappingsString = mappingsString + Base64VLQFormat.encode(mappedPosition.sourceLine - 1 - prevSourceLine);
prevSourceLine = mappedPosition.sourceLine - 1;
// 4. Relative sourceColumn 0 based
mappingsString = mappingsString + Base64VLQFormat.encode(mappedPosition.sourceColumn - prevSourceColumn);
prevSourceColumn = mappedPosition.sourceColumn;
// 5. Relative namePosition 0 based
if (nameIndex >= 0) {
mappingsString = mappingsString + Base64VLQFormat.encode(nameIndex - prevNameIndex);
prevNameIndex = nameIndex;
}
emitComma = true;
recordedPosition = mappedPosition;
};
// Record starting spans
var recordSourceMappingSiblings = (sourceMappings: SourceMapping[]) => {
for (var i = 0; i < sourceMappings.length; i++) {
var sourceMapping = sourceMappings[i];
recordSourceMapping(sourceMapping.start, sourceMapping.nameIndex);
recordSourceMappingSiblings(sourceMapping.childMappings);
recordSourceMapping(sourceMapping.end, sourceMapping.nameIndex);
}
};
recordSourceMappingSiblings(this.allSourceMappings[sourceIndex]);
}
// Write the actual map file
this.sourceMapOut.Write(JSON.stringify({
version: 3,
file: this.jsFileName,
sourceRoot: this.sourceRoot,
sources: this.tsFilePaths,
names: this.names,
mappings: mappingsString
}));
// Closing files could result in exceptions, report them if they occur
this.sourceMapOut.Close();
}
}
}
+736
View File
@@ -0,0 +1,736 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='typescript.ts'/>
///<reference path='io.ts'/>
///<reference path='optionsParser.ts'/>
module TypeScript {
class SourceFile {
constructor(public scriptSnapshot: IScriptSnapshot, public byteOrderMark: ByteOrderMark) {
}
}
class DiagnosticsLogger implements ILogger {
constructor(public ioHost: IEnvironment) {
}
public information(): boolean { return false; }
public debug(): boolean { return false; }
public warning(): boolean { return false; }
public error(): boolean { return false; }
public fatal(): boolean { return false; }
public log(s: string): void {
this.ioHost.standardOut.WriteLine(s);
}
}
export class BatchCompiler implements IReferenceResolverHost {
public compilerVersion = "1.0.1.0";
private inputFiles: string[] = [];
private compilationSettings: ImmutableCompilationSettings;
private resolvedFiles: IResolvedFile[] = [];
private fileNameToSourceFile = new StringHashTable<SourceFile>();
private hasErrors: boolean = false;
private logger: ILogger = null;
constructor(private ioHost: IEnvironment) {
}
// Begin batch compilation
public batchCompile() {
// Parse command line options
if (this.parseOptions()) {
var start = new Date().getTime();
if (this.compilationSettings.gatherDiagnostics()) {
this.logger = new DiagnosticsLogger(this.ioHost);
} else {
this.logger = new NullLogger();
}
if (this.compilationSettings.watch()) {
// Watch will cause the program to stick around as long as the files exist
this.watchFiles();
return;
}
// Resolve the compilation environemnt
this.resolve();
this.compile();
if (this.compilationSettings.gatherDiagnostics()) {
this.logger.log("");
this.logger.log("File resolution time: " + TypeScript.fileResolutionTime);
this.logger.log(" file read: " + TypeScript.fileResolutionIOTime);
this.logger.log(" scan imports: " + TypeScript.fileResolutionScanImportsTime);
this.logger.log(" import search: " + TypeScript.fileResolutionImportFileSearchTime);
this.logger.log(" get lib.d.ts: " + TypeScript.fileResolutionGetDefaultLibraryTime);
this.logger.log("SyntaxTree parse time: " + TypeScript.syntaxTreeParseTime);
this.logger.log("Syntax Diagnostics time: " + TypeScript.syntaxDiagnosticsTime);
this.logger.log("Create declarations time: " + TypeScript.createDeclarationsTime);
this.logger.log("");
this.logger.log("Type check time: " + TypeScript.typeCheckTime);
this.logger.log("");
this.logger.log("Emit time: " + TypeScript.emitTime);
this.logger.log("Declaration emit time: " + TypeScript.declarationEmitTime);
this.logger.log("Total number of symbols created: " + TypeScript.pullSymbolID);
this.logger.log("Specialized types created: " + TypeScript.nSpecializationsCreated);
this.logger.log("Specialized signatures created: " + TypeScript.nSpecializedSignaturesCreated);
this.logger.log(" IsExternallyVisibleTime: " + TypeScript.declarationEmitIsExternallyVisibleTime);
this.logger.log(" TypeSignatureTime: " + TypeScript.declarationEmitTypeSignatureTime);
this.logger.log(" GetBoundDeclTypeTime: " + TypeScript.declarationEmitGetBoundDeclTypeTime);
this.logger.log(" IsOverloadedCallSignatureTime: " + TypeScript.declarationEmitIsOverloadedCallSignatureTime);
this.logger.log(" FunctionDeclarationGetSymbolTime: " + TypeScript.declarationEmitFunctionDeclarationGetSymbolTime);
this.logger.log(" GetBaseTypeTime: " + TypeScript.declarationEmitGetBaseTypeTime);
this.logger.log(" GetAccessorFunctionTime: " + TypeScript.declarationEmitGetAccessorFunctionTime);
this.logger.log(" GetTypeParameterSymbolTime: " + TypeScript.declarationEmitGetTypeParameterSymbolTime);
this.logger.log(" GetImportDeclarationSymbolTime: " + TypeScript.declarationEmitGetImportDeclarationSymbolTime);
this.logger.log("Emit write file time: " + TypeScript.emitWriteFileTime);
this.logger.log("Compiler resolve path time: " + TypeScript.compilerResolvePathTime);
this.logger.log("Compiler directory name time: " + TypeScript.compilerDirectoryNameTime);
this.logger.log("Compiler directory exists time: " + TypeScript.compilerDirectoryExistsTime);
this.logger.log("Compiler file exists time: " + TypeScript.compilerFileExistsTime);
this.logger.log("IO host resolve path time: " + TypeScript.ioHostResolvePathTime);
this.logger.log("IO host directory name time: " + TypeScript.ioHostDirectoryNameTime);
this.logger.log("IO host create directory structure time: " + TypeScript.ioHostCreateDirectoryStructureTime);
this.logger.log("IO host write file time: " + TypeScript.ioHostWriteFileTime);
this.logger.log("Node make directory time: " + TypeScript.nodeMakeDirectoryTime);
this.logger.log("Node writeFileSync time: " + TypeScript.nodeWriteFileSyncTime);
this.logger.log("Node createBuffer time: " + TypeScript.nodeCreateBufferTime);
this.logger.log("Total time: " + (new Date().getTime() - start));
}
}
// Exit with the appropriate error code
this.ioHost.quit(this.hasErrors ? 1 : 0);
}
private resolve() {
// Resolve file dependencies, if requested
var includeDefaultLibrary = !this.compilationSettings.noLib();
var resolvedFiles: IResolvedFile[] = [];
var start = new Date().getTime();
if (!this.compilationSettings.noResolve()) {
// Resolve references
var resolutionResults = ReferenceResolver.resolve(this.inputFiles, this, this.compilationSettings.useCaseSensitiveFileResolution());
resolvedFiles = resolutionResults.resolvedFiles;
// Only include the library if useDefaultLib is set to true and did not see any 'no-default-lib' comments
includeDefaultLibrary = !this.compilationSettings.noLib() && !resolutionResults.seenNoDefaultLibTag;
// Populate any diagnostic messages generated during resolution
resolutionResults.diagnostics.forEach(d => this.addDiagnostic(d));
}
else {
for (var i = 0, n = this.inputFiles.length; i < n; i++) {
var inputFile = this.inputFiles[i];
var referencedFiles: string[] = [];
var importedFiles: string[] = [];
// If declaration files are going to be emitted, preprocess the file contents and add in referenced files as well
if (this.compilationSettings.generateDeclarationFiles()) {
var references = getReferencedFiles(inputFile, this.getScriptSnapshot(inputFile));
for (var j = 0; j < references.length; j++) {
referencedFiles.push(references[j].path);
}
inputFile = this.resolvePath(inputFile);
}
resolvedFiles.push({
path: inputFile,
referencedFiles: referencedFiles,
importedFiles: importedFiles
});
}
}
var defaultLibStart = new Date().getTime();
if (includeDefaultLibrary) {
var libraryResolvedFile: IResolvedFile = {
path: this.getDefaultLibraryFilePath(),
referencedFiles: [],
importedFiles: []
};
// Prepend the library to the resolved list
resolvedFiles = [libraryResolvedFile].concat(resolvedFiles);
}
TypeScript.fileResolutionGetDefaultLibraryTime += new Date().getTime() - defaultLibStart;
this.resolvedFiles = resolvedFiles;
TypeScript.fileResolutionTime = new Date().getTime() - start;
}
// Returns true if compilation failed from some reason.
private compile(): void {
var compiler = new TypeScriptCompiler(this.logger, this.compilationSettings);
this.resolvedFiles.forEach(resolvedFile => {
var sourceFile = this.getSourceFile(resolvedFile.path);
compiler.addFile(resolvedFile.path, sourceFile.scriptSnapshot, sourceFile.byteOrderMark, /*version:*/ 0, /*isOpen:*/ false, resolvedFile.referencedFiles);
});
for (var it = compiler.compile((path: string) => this.resolvePath(path)); it.moveNext();) {
var result = it.current();
result.diagnostics.forEach(d => this.addDiagnostic(d));
if (!this.tryWriteOutputFiles(result.outputFiles)) {
return;
}
}
}
// Parse command line options
private parseOptions() {
var opts = new OptionsParser(this.ioHost, this.compilerVersion);
var mutableSettings = new CompilationSettings();
opts.option('out', {
usage: {
locCode: DiagnosticCode.Concatenate_and_emit_output_to_single_file,
args: null
},
type: DiagnosticCode.file2,
set: (str) => {
mutableSettings.outFileOption = str;
}
});
opts.option('outDir', {
usage: {
locCode: DiagnosticCode.Redirect_output_structure_to_the_directory,
args: null
},
type: DiagnosticCode.DIRECTORY,
set: (str) => {
mutableSettings.outDirOption = str;
}
});
opts.flag('sourcemap', {
usage: {
locCode: DiagnosticCode.Generates_corresponding_0_file,
args: ['.map']
},
set: () => {
mutableSettings.mapSourceFiles = true;
}
});
opts.option('mapRoot', {
usage: {
locCode: DiagnosticCode.Specifies_the_location_where_debugger_should_locate_map_files_instead_of_generated_locations,
args: null
},
type: DiagnosticCode.LOCATION,
set: (str) => {
mutableSettings.mapRoot = str;
}
});
opts.option('sourceRoot', {
usage: {
locCode: DiagnosticCode.Specifies_the_location_where_debugger_should_locate_TypeScript_files_instead_of_source_locations,
args: null
},
type: DiagnosticCode.LOCATION,
set: (str) => {
mutableSettings.sourceRoot = str;
}
});
opts.flag('declaration', {
usage: {
locCode: DiagnosticCode.Generates_corresponding_0_file,
args: ['.d.ts']
},
set: () => {
mutableSettings.generateDeclarationFiles = true;
}
}, 'd');
if (this.ioHost.watchFile) {
opts.flag('watch', {
usage: {
locCode: DiagnosticCode.Watch_input_files,
args: null
},
set: () => {
mutableSettings.watch = true;
}
}, 'w');
}
opts.flag('propagateEnumConstants', {
experimental: true,
set: () => { mutableSettings.propagateEnumConstants = true; }
});
opts.flag('removeComments', {
usage: {
locCode: DiagnosticCode.Do_not_emit_comments_to_output,
args: null
},
set: () => {
mutableSettings.removeComments = true;
}
});
opts.flag('noResolve', {
experimental: true,
usage: {
locCode: DiagnosticCode.Skip_resolution_and_preprocessing,
args: null
},
set: () => {
mutableSettings.noResolve = true;
}
});
opts.flag('noLib', {
experimental: true,
set: () => {
mutableSettings.noLib = true;
}
});
opts.flag('diagnostics', {
experimental: true,
set: () => {
mutableSettings.gatherDiagnostics = true;
}
});
opts.option('target', {
usage: {
locCode: DiagnosticCode.Specify_ECMAScript_target_version_0_default_or_1,
args: ['ES3', 'ES5']
},
type: DiagnosticCode.VERSION,
set: (type) => {
type = type.toLowerCase();
if (type === 'es3') {
mutableSettings.codeGenTarget = LanguageVersion.EcmaScript3;
}
else if (type === 'es5') {
mutableSettings.codeGenTarget = LanguageVersion.EcmaScript5;
}
else {
this.addDiagnostic(
new Diagnostic(null, null, 0, 0, DiagnosticCode.Argument_for_0_option_must_be_1_or_2, ["target", "ES3", "ES5"]));
}
}
}, 't');
opts.option('module', {
usage: {
locCode: DiagnosticCode.Specify_module_code_generation_0_or_1,
args: ['commonjs', 'amd']
},
type: DiagnosticCode.KIND,
set: (type) => {
type = type.toLowerCase();
if (type === 'commonjs') {
mutableSettings.moduleGenTarget = ModuleGenTarget.Synchronous;
}
else if (type === 'amd') {
mutableSettings.moduleGenTarget = ModuleGenTarget.Asynchronous;
}
else {
this.addDiagnostic(
new Diagnostic(null, null, 0, 0, DiagnosticCode.Argument_for_0_option_must_be_1_or_2, ["module", "commonjs", "amd"]));
}
}
}, 'm');
var needsHelp = false;
opts.flag('help', {
usage: {
locCode: DiagnosticCode.Print_this_message,
args: null
},
set: () => {
needsHelp = true;
}
}, 'h');
opts.flag('useCaseSensitiveFileResolution', {
experimental: true,
set: () => {
mutableSettings.useCaseSensitiveFileResolution = true;
}
});
var shouldPrintVersionOnly = false;
opts.flag('version', {
usage: {
locCode: DiagnosticCode.Print_the_compiler_s_version_0,
args: [this.compilerVersion]
},
set: () => {
shouldPrintVersionOnly = true;
}
}, 'v');
var locale: string = null;
opts.option('locale', {
experimental: true,
usage: {
locCode: DiagnosticCode.Specify_locale_for_errors_and_messages_For_example_0_or_1,
args: ['en', 'ja-jp']
},
type: DiagnosticCode.STRING,
set: (value) => {
locale = value;
}
});
opts.flag('noImplicitAny', {
usage: {
locCode: DiagnosticCode.Warn_on_expressions_and_declarations_with_an_implied_any_type,
args: null
},
set: () => {
mutableSettings.noImplicitAny = true;
}
});
if (Environment.supportsCodePage()) {
opts.option('codepage', {
usage: {
locCode: DiagnosticCode.Specify_the_codepage_to_use_when_opening_source_files,
args: null
},
type: DiagnosticCode.NUMBER,
set: (arg) => {
mutableSettings.codepage = parseInt(arg, 10);
}
});
}
opts.parse(this.ioHost.arguments);
this.compilationSettings = ImmutableCompilationSettings.fromCompilationSettings(mutableSettings);
if (locale) {
if (!this.setLocale(locale)) {
return false;
}
}
this.inputFiles.push.apply(this.inputFiles, opts.unnamed);
if (shouldPrintVersionOnly) {
opts.printVersion();
return false;
}
// If no source files provided to compiler - print usage information
else if (this.inputFiles.length === 0 || needsHelp) {
opts.printUsage();
return false;
}
return !this.hasErrors;
}
private setLocale(locale: string): boolean {
var matchResult = /^([a-z]+)([_\-]([a-z]+))?$/.exec(locale.toLowerCase());
if (!matchResult) {
this.addDiagnostic(new Diagnostic(null, null, 0, 0, DiagnosticCode.Locale_must_be_of_the_form_language_or_language_territory_For_example_0_or_1, ['en', 'ja-jp']));
return false;
}
var language = matchResult[1];
var territory = matchResult[3];
// First try the entire locale, then fall back to just language if that's all we have.
if (!this.setLanguageAndTerritory(language, territory) &&
!this.setLanguageAndTerritory(language, null)) {
this.addDiagnostic(new Diagnostic(null, null, 0, 0, DiagnosticCode.Unsupported_locale_0, [locale]));
return false;
}
return true;
}
private setLanguageAndTerritory(language: string, territory: string): boolean {
var compilerFilePath = this.ioHost.executingFilePath();
var containingDirectoryPath = this.ioHost.directoryName(compilerFilePath);
var filePath = IOUtils.combine(containingDirectoryPath, language);
if (territory) {
filePath = filePath + "-" + territory;
}
filePath = this.resolvePath(IOUtils.combine(filePath, "diagnosticMessages.generated.json"));
if (!this.fileExists(filePath)) {
return false;
}
var fileContents = this.ioHost.readFile(filePath, this.compilationSettings.codepage());
TypeScript.LocalizedDiagnosticMessages = JSON.parse(fileContents.contents);
return true;
}
// Handle -watch switch
private watchFiles() {
if (!this.ioHost.watchFile) {
this.addDiagnostic(
new Diagnostic(null, null, 0, 0, DiagnosticCode.Current_host_does_not_support_0_option, ['-w[atch]']));
return;
}
var lastResolvedFileSet: string[] = []
var watchers: { [x: string]: IFileWatcher; } = {};
var firstTime = true;
var addWatcher = (fileName: string) => {
if (!watchers[fileName]) {
var watcher = this.ioHost.watchFile(fileName, onWatchedFileChange);
watchers[fileName] = watcher;
}
};
var removeWatcher = (fileName: string) => {
if (watchers[fileName]) {
watchers[fileName].close();
delete watchers[fileName];
}
};
var onWatchedFileChange = () => {
// Clean errors for previous compilation
this.hasErrors = false;
// Clear out any source file data we've cached.
this.fileNameToSourceFile = new StringHashTable<SourceFile>();
// Resolve file dependencies, if requested
this.resolve();
// Check if any new files were added to the environment as a result of the file change
var oldFiles = lastResolvedFileSet;
var newFiles = this.resolvedFiles.map(resolvedFile => resolvedFile.path).sort();
var i = 0, j = 0;
while (i < oldFiles.length && j < newFiles.length) {
var compareResult = oldFiles[i].localeCompare(newFiles[j]);
if (compareResult === 0) {
// No change here
i++;
j++;
}
else if (compareResult < 0) {
// Entry in old list does not exist in the new one, it was removed
removeWatcher(oldFiles[i]);
i++;
}
else {
// Entry in new list does exist in the new one, it was added
addWatcher(newFiles[j]);
j++;
}
}
// All remaining unmatched items in the old list have been removed
for (var k = i; k < oldFiles.length; k++) {
removeWatcher(oldFiles[k]);
}
// All remaing unmatched items in the new list have been added
for (k = j; k < newFiles.length; k++) {
addWatcher(newFiles[k]);
}
// Update the state
lastResolvedFileSet = newFiles;
// Print header
if (!firstTime) {
var fileNames = "";
for (var k = 0; k < lastResolvedFileSet.length; k++) {
fileNames += Environment.newLine + " " + lastResolvedFileSet[k];
}
this.ioHost.standardError.WriteLine(getLocalizedText(DiagnosticCode.NL_Recompiling_0, [fileNames]));
}
else {
firstTime = false;
}
// Trigger a new compilation
this.compile();
};
// Switch to using stdout for all error messages
this.ioHost.standardOut = this.ioHost.standardOut;
onWatchedFileChange();
}
private getSourceFile(fileName: string): SourceFile {
var sourceFile: SourceFile = this.fileNameToSourceFile.lookup(fileName);
if (!sourceFile) {
// Attempt to read the file
var fileInformation: FileInformation;
try {
fileInformation = this.ioHost.readFile(fileName, this.compilationSettings.codepage());
}
catch (e) {
this.addDiagnostic(new Diagnostic(null, null, 0, 0, DiagnosticCode.Cannot_read_file_0_1, [fileName, e.message]));
fileInformation = new FileInformation("", ByteOrderMark.None);
}
var snapshot = ScriptSnapshot.fromString(fileInformation.contents);
var sourceFile = new SourceFile(snapshot, fileInformation.byteOrderMark);
this.fileNameToSourceFile.add(fileName, sourceFile);
}
return sourceFile;
}
private getDefaultLibraryFilePath(): string {
var compilerFilePath = this.ioHost.executingFilePath();
var containingDirectoryPath = this.ioHost.directoryName(compilerFilePath);
var libraryFilePath = this.resolvePath(IOUtils.combine(containingDirectoryPath, "lib.d.ts"));
return libraryFilePath;
}
/// IReferenceResolverHost methods
getScriptSnapshot(fileName: string): IScriptSnapshot {
return this.getSourceFile(fileName).scriptSnapshot;
}
resolveRelativePath(path: string, directory: string): string {
var unQuotedPath = stripStartAndEndQuotes(path);
var normalizedPath: string;
if (isRooted(unQuotedPath) || !directory) {
normalizedPath = unQuotedPath;
} else {
normalizedPath = IOUtils.combine(directory, unQuotedPath);
}
// get the absolute path
normalizedPath = this.resolvePath(normalizedPath);
// Switch to forward slashes
normalizedPath = switchToForwardSlashes(normalizedPath);
return normalizedPath;
}
private fileExistsCache = createIntrinsicsObject<boolean>();
fileExists(path: string): boolean {
var exists = this.fileExistsCache[path];
if (exists === undefined) {
var start = new Date().getTime();
exists = this.ioHost.fileExists(path);
this.fileExistsCache[path] = exists;
TypeScript.compilerFileExistsTime += new Date().getTime() - start;
}
return exists;
}
getParentDirectory(path: string): string {
var start = new Date().getTime();
var result = this.ioHost.directoryName(path);
TypeScript.compilerDirectoryNameTime += new Date().getTime() - start;
return result;
}
private addDiagnostic(diagnostic: Diagnostic): void {
var diagnosticInfo = diagnostic.info();
if (diagnosticInfo.category === DiagnosticCategory.Error) {
this.hasErrors = true;
}
this.ioHost.standardError.Write(TypeScriptCompiler.getFullDiagnosticText(diagnostic, path => this.resolvePath(path)));
}
private tryWriteOutputFiles(outputFiles: OutputFile[]): boolean {
for (var i = 0, n = outputFiles.length; i < n; i++) {
var outputFile = outputFiles[i];
try {
this.writeFile(outputFile.name, outputFile.text, outputFile.writeByteOrderMark);
}
catch (e) {
this.addDiagnostic(
new Diagnostic(outputFile.name, null, 0, 0, DiagnosticCode.Emit_Error_0, [e.message]));
return false;
}
}
return true;
}
writeFile(fileName: string, contents: string, writeByteOrderMark: boolean): void {
var start = new Date().getTime();
IOUtils.writeFileAndFolderStructure(this.ioHost, fileName, contents, writeByteOrderMark);
TypeScript.emitWriteFileTime += new Date().getTime() - start;
}
directoryExists(path: string): boolean {
var start = new Date().getTime();
var result = this.ioHost.directoryExists(path);
TypeScript.compilerDirectoryExistsTime += new Date().getTime() - start;
return result;
}
// For performance reasons we cache the results of resolvePath. This avoids costly lookup
// on the disk once we've already resolved a path once.
private resolvePathCache = createIntrinsicsObject<string>();
resolvePath(path: string): string {
var cachedValue = this.resolvePathCache[path];
if (!cachedValue) {
var start = new Date().getTime();
cachedValue = this.ioHost.absolutePath(path);
this.resolvePathCache[path] = cachedValue;
TypeScript.compilerResolvePathTime += new Date().getTime() - start;
}
return cachedValue;
}
}
// Start the batch compilation using the current hosts IO
var batch = new TypeScript.BatchCompiler(Environment);
batch.batchCompile();
}
+102
View File
@@ -0,0 +1,102 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='references.ts' />
module TypeScript {
export class MemberName {
public prefix: string = "";
public suffix: string = "";
public isString() { return false; }
public isArray() { return false; }
public isMarker() { return !this.isString() && !this.isArray(); }
public toString(): string {
return MemberName.memberNameToString(this);
}
static memberNameToString(memberName: MemberName, markerInfo?: number[], markerBaseLength: number = 0): string {
var result = memberName.prefix;
if (memberName.isString()) {
result += (<MemberNameString>memberName).text;
}
else if (memberName.isArray()) {
var ar = <MemberNameArray>memberName;
for (var index = 0; index < ar.entries.length; index++) {
if (ar.entries[index].isMarker()) {
if (markerInfo) {
markerInfo.push(markerBaseLength + result.length);
}
continue;
}
result += MemberName.memberNameToString(ar.entries[index], markerInfo, markerBaseLength + result.length);
result += ar.delim;
}
}
result += memberName.suffix;
return result;
}
static create(text: string): MemberName;
static create(entry: MemberName, prefix: string, suffix: string): MemberName;
static create(arg1: any, arg2?: any, arg3?: any): MemberName {
if (typeof arg1 === "string") {
return new MemberNameString(arg1);
}
else {
var result = new MemberNameArray();
if (arg2)
result.prefix = arg2;
if (arg3)
result.suffix = arg3;
result.entries.push(arg1);
return result;
}
}
}
export class MemberNameString extends MemberName {
constructor(public text: string) {
super();
}
public isString() { return true; }
}
export class MemberNameArray extends MemberName {
public delim: string = "";
public entries: MemberName[] = [];
public isArray() { return true; }
public add(entry: MemberName) {
this.entries.push(entry);
}
public addAll(entries: MemberName[]) {
for (var i = 0 ; i < entries.length; i++) {
this.entries.push(entries[i]);
}
}
constructor() {
super();
}
}
}
File diff suppressed because it is too large Load Diff
+31
View File
@@ -0,0 +1,31 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='typescript.ts' />
module Tools {
export interface IWalkContext {
goChildren: boolean;
goNextSibling: boolean;
// visit siblings in reverse execution order
reverseSiblings: boolean;
}
export class BaseWalkContext implements IWalkContext {
public goChildren = true;
public goNextSibling = true;
public reverseSiblings = false;
}
}
+205
View File
@@ -0,0 +1,205 @@
///<reference path='references.ts' />
module TypeScript {
export class ArrayUtilities {
public static sequenceEquals<T>(array1: T[], array2: T[], equals: (v1: T, v2: T) => boolean) {
if (array1 === array2) {
return true;
}
if (array1 === null || array2 === null) {
return false;
}
if (array1.length !== array2.length) {
return false;
}
for (var i = 0, n = array1.length; i < n; i++) {
if (!equals(array1[i], array2[i])) {
return false;
}
}
return true;
}
public static contains<T>(array: T[], value: T): boolean {
for (var i = 0; i < array.length; i++) {
if (array[i] === value) {
return true;
}
}
return false;
}
// Gets unique element array
public static distinct<T>(array: T[], equalsFn?: (a: T, b: T) => boolean): T[] {
var result: T[] = [];
// TODO: use map when available
for (var i = 0, n = array.length; i < n; i++) {
var current = array[i];
for (var j = 0; j < result.length; j++) {
if (equalsFn(result[j], current)) {
break;
}
}
if (j === result.length) {
result.push(current);
}
}
return result;
}
public static last<T>(array: T[]): T {
if (array.length === 0) {
throw Errors.argumentOutOfRange('array');
}
return array[array.length - 1];
}
public static lastOrDefault<T>(array: T[], predicate: (v: T, index: number) => boolean): T {
for (var i = array.length - 1; i >= 0; i--) {
var v = array[i];
if (predicate(v, i)) {
return v;
}
}
return null;
}
public static firstOrDefault<T>(array: T[], func: (v: T, index: number) => boolean): T {
for (var i = 0, n = array.length; i < n; i++) {
var value = array[i];
if (func(value, i)) {
return value;
}
}
return null;
}
public static first<T>(array: T[], func?: (v: T, index: number) => boolean): T {
for (var i = 0, n = array.length; i < n; i++) {
var value = array[i];
if (!func || func(value, i)) {
return value;
}
}
throw Errors.invalidOperation();
}
public static sum<T>(array: T[], func: (v: T) => number): number {
var result = 0;
for (var i = 0, n = array.length; i < n; i++) {
result += func(array[i]);
}
return result;
}
public static select<T,S>(values: T[], func: (v: T) => S): S[] {
var result: S[] = new Array<S>(values.length);
for (var i = 0; i < values.length; i++) {
result[i] = func(values[i]);
}
return result;
}
public static where<T>(values: T[], func: (v: T) => boolean): T[] {
var result = new Array<T>();
for (var i = 0; i < values.length; i++) {
if (func(values[i])) {
result.push(values[i]);
}
}
return result;
}
public static any<T>(array: T[], func: (v: T) => boolean): boolean {
for (var i = 0, n = array.length; i < n; i++) {
if (func(array[i])) {
return true;
}
}
return false;
}
public static all<T>(array: T[], func: (v: T) => boolean): boolean {
for (var i = 0, n = array.length; i < n; i++) {
if (!func(array[i])) {
return false;
}
}
return true;
}
public static binarySearch(array: number[], value: number): number {
var low = 0;
var high = array.length - 1;
while (low <= high) {
var middle = low + ((high - low) >> 1);
var midValue = array[middle];
if (midValue === value) {
return middle;
}
else if (midValue > value) {
high = middle - 1;
}
else {
low = middle + 1;
}
}
return ~low;
}
public static createArray<T>(length: number, defaultValue: any): T[] {
var result = new Array<T>(length);
for (var i = 0; i < length; i++) {
result[i] = defaultValue;
}
return result;
}
public static grow<T>(array: T[], length: number, defaultValue: T): void {
var count = length - array.length;
for (var i = 0; i < count; i++) {
array.push(defaultValue);
}
}
public static copy<T>(sourceArray: T[], sourceIndex: number, destinationArray: T[], destinationIndex: number, length: number): void {
for (var i = 0; i < length; i++) {
destinationArray[destinationIndex + i] = sourceArray[sourceIndex + i];
}
}
public static indexOf<T>(array: T[], predicate: (v: T) => boolean): number {
for (var i = 0, n = array.length; i < n; i++) {
if (predicate(array[i])) {
return i;
}
}
return -1;
}
}
}
+32
View File
@@ -0,0 +1,32 @@
///<reference path='references.ts' />
module TypeScript {
export enum AssertionLevel {
None = 0,
Normal = 1,
Aggressive = 2,
VeryAggressive = 3,
}
export class Debug {
private static currentAssertionLevel = AssertionLevel.None;
public static shouldAssert(level: AssertionLevel): boolean {
return this.currentAssertionLevel >= level;
}
public static assert(expression: any, message: string = "", verboseDebugInfo: () => string = null): void {
if (!expression) {
var verboseDebugString = "";
if (verboseDebugInfo) {
verboseDebugString = "\r\nVerbose Debug Information:" + verboseDebugInfo();
}
throw new Error("Debug Failure. False expression: " + message + verboseDebugString);
}
}
public static fail(message?: string): void {
Debug.assert(false, message);
}
}
}
+10
View File
@@ -0,0 +1,10 @@
///<reference path='references.ts' />
module TypeScript {
export enum DiagnosticCategory {
Warning,
Error,
Message,
NoPrefix,
}
}
+197
View File
@@ -0,0 +1,197 @@
///<reference path='references.ts' />
module TypeScript {
export var LocalizedDiagnosticMessages: ts.Map<any> = null;
export class Location {
private _fileName: string;
private _lineMap: LineMap;
private _start: number;
private _length: number;
constructor(fileName: string, lineMap: LineMap, start: number, length: number) {
this._fileName = fileName;
this._lineMap = lineMap;
this._start = start;
this._length = length;
}
public fileName(): string {
return this._fileName;
}
public lineMap(): LineMap {
return this._lineMap;
}
public line(): number {
return this._lineMap ? this._lineMap.getLineNumberFromPosition(this.start()) : 0;
}
public character(): number {
return this._lineMap ? this._lineMap.getLineAndCharacterFromPosition(this.start()).character() : 0;
}
public start(): number {
return this._start;
}
public length(): number {
return this._length;
}
public static equals(location1: Location, location2: Location): boolean {
return location1._fileName === location2._fileName &&
location1._start === location2._start &&
location1._length === location2._length;
}
}
export class Diagnostic extends Location {
private _diagnosticKey: string;
private _arguments: any[];
private _additionalLocations: Location[];
constructor(fileName: string, lineMap: LineMap, start: number, length: number, diagnosticKey: string, _arguments: any[]= null, additionalLocations: Location[] = null) {
super(fileName, lineMap, start, length);
this._diagnosticKey = diagnosticKey;
this._arguments = (_arguments && _arguments.length > 0) ? _arguments : null;
this._additionalLocations = (additionalLocations && additionalLocations.length > 0) ? additionalLocations : null;
}
public toJSON(key: any): any {
var result: any = {};
result.start = this.start();
result.length = this.length();
result.diagnosticCode = this._diagnosticKey;
var _arguments: any[] = (<any>this).arguments();
if (_arguments && _arguments.length > 0) {
result.arguments = _arguments;
}
return result;
}
public diagnosticKey(): string {
return this._diagnosticKey;
}
public arguments(): any[] {
return this._arguments;
}
/**
* Get the text of the message in the given language.
*/
public text(): string {
return TypeScript.getLocalizedText(this._diagnosticKey, this._arguments);
}
/**
* Get the text of the message including the error code in the given language.
*/
public message(): string {
return TypeScript.getDiagnosticMessage(this._diagnosticKey, this._arguments);
}
/**
* If a derived class has additional information about other referenced symbols, it can
* expose the locations of those symbols in a general way, so they can be reported along
* with the error.
*/
public additionalLocations(): Location[] {
return this._additionalLocations || [];
}
public static equals(diagnostic1: Diagnostic, diagnostic2: Diagnostic): boolean {
return Location.equals(diagnostic1, diagnostic2) &&
diagnostic1._diagnosticKey === diagnostic2._diagnosticKey &&
ArrayUtilities.sequenceEquals(diagnostic1._arguments, diagnostic2._arguments, (v1, v2) => v1 === v2);
}
public info(): DiagnosticInfo {
return getDiagnosticInfoFromKey(this.diagnosticKey());
}
}
export function newLine(): string {
// TODO: We need to expose an extensibility point on our hosts to have them tell us what
// they want the newline string to be. That way we can get the correct result regardless
// of which host we use
return sys.newLine ? sys.newLine : "\r\n";
}
function getLargestIndex(diagnostic: string): number {
var largest = -1;
var regex = /\{(\d+)\}/g;
var match: RegExpExecArray;
while (match = regex.exec(diagnostic)) {
var val = parseInt(match[1]);
if (!isNaN(val) && val > largest) {
largest = val;
}
}
return largest;
}
function getDiagnosticInfoFromKey(diagnosticKey: string): DiagnosticInfo {
var result: DiagnosticInfo = diagnosticInformationMap[diagnosticKey];
Debug.assert(result);
return result;
}
export function getLocalizedText(diagnosticKey: string, args: any[]): string {
var diagnosticMessageText: string = diagnosticKey;
Debug.assert(diagnosticMessageText !== undefined && diagnosticMessageText !== null);
var actualCount = args ? args.length : 0;
// We have a string like "foo_0_bar_1". We want to find the largest integer there.
// (i.e.'1'). We then need one more arg than that to be correct.
var expectedCount = 1 + getLargestIndex(diagnosticKey);
if (expectedCount !== actualCount) {
throw new Error(getLocalizedText(DiagnosticCode.Expected_0_arguments_to_message_got_1_instead, [expectedCount, actualCount]));
}
// This should also be the same number of arguments as the message text
var valueCount = 1 + getLargestIndex(diagnosticMessageText);
if (valueCount !== expectedCount) {
throw new Error(getLocalizedText(DiagnosticCode.Expected_the_message_0_to_have_1_arguments_but_it_had_2, [diagnosticMessageText, expectedCount, valueCount]));
}
diagnosticMessageText = diagnosticMessageText.replace(/{(\d+)}/g, function (match, num?) {
return typeof args[num] !== 'undefined'
? args[num]
: match;
});
diagnosticMessageText = diagnosticMessageText.replace(/{(NL)}/g, function (match) {
return TypeScript.newLine();
});
return diagnosticMessageText;
}
export function getDiagnosticMessage(diagnosticKey: string, args: any[]): string {
var diagnostic = getDiagnosticInfoFromKey(diagnosticKey);
var diagnosticMessageText = getLocalizedText(diagnosticKey, args);
var message: string;
if (diagnostic.category === DiagnosticCategory.Error) {
message = getLocalizedText(DiagnosticCode.error_TS_0_1, [diagnostic.code, diagnosticMessageText]);
}
else if (diagnostic.category === DiagnosticCategory.Warning) {
message = getLocalizedText(DiagnosticCode.warning_TS_0_1, [diagnostic.code, diagnosticMessageText]);
}
else {
message = diagnosticMessageText;
}
return message;
}
}
+9
View File
@@ -0,0 +1,9 @@
///<reference path='references.ts' />
module TypeScript {
export interface DiagnosticInfo {
category: DiagnosticCategory;
message: string;
code: number;
}
}
+29
View File
@@ -0,0 +1,29 @@
///<reference path='references.ts' />
module TypeScript {
export class Errors {
public static argument(argument: string, message?: string): Error {
return new Error("Invalid argument: " + argument + ". " + message);
}
public static argumentOutOfRange(argument: string): Error {
return new Error("Argument out of range: " + argument);
}
public static argumentNull(argument: string): Error {
return new Error("Argument null: " + argument);
}
public static abstract(): Error {
return new Error("Operation not implemented properly by subclass.");
}
public static notYetImplemented(): Error {
return new Error("Not yet implemented.");
}
public static invalidOperation(message?: string): Error {
return new Error("Invalid operation: " + message);
}
}
}
+112
View File
@@ -0,0 +1,112 @@
///<reference path='references.ts' />
module TypeScript {
export class Hash {
// This table uses FNV1a as a string hash
private static FNV_BASE = 2166136261;
private static FNV_PRIME = 16777619;
private static computeFnv1aCharArrayHashCode(text: number[], start: number, len: number): number {
var hashCode = Hash.FNV_BASE;
var end = start + len;
for (var i = start; i < end; i++) {
hashCode = IntegerUtilities.integerMultiplyLow32Bits(hashCode ^ text[i], Hash.FNV_PRIME);
}
return hashCode;
}
public static computeSimple31BitCharArrayHashCode(key: number[], start: number, len: number): number {
// Start with an int.
var hash = 0;
for (var i = 0; i < len; i++) {
var ch = key[start + i];
// Left shift keeps things as a 32bit int. And we're only doing two adds. Chakra and
// V8 recognize this as not needing to go past the 53 bits needed for the float
// mantissa. Or'ing with 0 keeps this 32 bits.
hash = ((((hash << 5) - hash) | 0) + ch) | 0;
}
// Ensure we fit in 31 bits. That way if/when this gets stored, it won't require any heap
// allocation.
return hash & 0x7FFFFFFF;
}
public static computeSimple31BitStringHashCode(key: string): number {
// Start with an int.
var hash = 0;
var start = 0;
var len = key.length;
for (var i = 0; i < len; i++) {
var ch = key.charCodeAt(start + i);
// Left shift keeps things as a 32bit int. And we're only doing two adds. Chakra and
// V8 recognize this as not needing to go past the 53 bits needed for the float
// mantissa. Or'ing with 0 keeps this 32 bits.
hash = ((((hash << 5) - hash) | 0) + ch) | 0;
}
// Ensure we fit in 31 bits. That way if/when this gets stored, it won't require any heap
// allocation.
return hash & 0x7FFFFFFF;
}
public static computeMurmur2StringHashCode(key: string, seed: number): number {
// 'm' and 'r' are mixing constants generated offline.
// They're not really 'magic', they just happen to work well.
var m: number = 0x5bd1e995;
var r: number = 24;
// Initialize the hash to a 'random' value
var numberOfCharsLeft = key.length;
var h = Math.abs(seed ^ numberOfCharsLeft);
// Mix 4 bytes at a time into the hash. NOTE: 4 bytes is two chars, so we iterate
// through the string two chars at a time.
var index = 0;
while (numberOfCharsLeft >= 2) {
var c1 = key.charCodeAt(index);
var c2 = key.charCodeAt(index + 1);
var k = Math.abs(c1 | (c2 << 16));
k = IntegerUtilities.integerMultiplyLow32Bits(k, m);
k ^= k >> r;
k = IntegerUtilities.integerMultiplyLow32Bits(k, m);
h = IntegerUtilities.integerMultiplyLow32Bits(h, m);
h ^= k;
index += 2;
numberOfCharsLeft -= 2;
}
// Handle the last char (or 2 bytes) if they exist. This happens if the original string had
// odd length.
if (numberOfCharsLeft === 1) {
h ^= key.charCodeAt(index);
h = IntegerUtilities.integerMultiplyLow32Bits(h, m);
}
// Do a few final mixes of the hash to ensure the last few bytes are well-incorporated.
h ^= h >> 13;
h = IntegerUtilities.integerMultiplyLow32Bits(h, m);
h ^= h >> 15;
return h;
}
public static combine(value: number, currentHash: number): number {
// Ensure we stay within 31 bits.
return (((currentHash << 5) + currentHash) + value) & 0x7FFFFFFF;
}
}
}
+28
View File
@@ -0,0 +1,28 @@
///<reference path='references.ts' />
module TypeScript {
export module IntegerUtilities {
export function integerDivide(numerator: number, denominator: number): number {
return (numerator / denominator) >> 0;
}
export function integerMultiplyLow32Bits(n1: number, n2: number): number {
var n1Low16 = n1 & 0x0000ffff;
var n1High16 = n1 >>> 16;
var n2Low16 = n2 & 0x0000ffff;
var n2High16 = n2 >>> 16;
var resultLow32 = (((n1 & 0xffff0000) * n2) >>> 0) + (((n1 & 0x0000ffff) * n2) >>> 0) >>> 0;
return resultLow32;
}
export function isInteger(text: string): boolean {
return /^[0-9]+$/.test(text);
}
export function isHexInteger(text: string): boolean {
return /^0(x|X)[0-9a-fA-F]+$/.test(text);
}
}
}
+82
View File
@@ -0,0 +1,82 @@
///<reference path='references.ts' />
module TypeScript {
export class LineMap {
public static empty = new LineMap(() => [0], 0);
private _lineStarts: number[] = null;
constructor(private _computeLineStarts: () => number[], private length: number) {
}
public toJSON(key: any) {
return { lineStarts: this.lineStarts(), length: this.length };
}
public equals(other: LineMap): boolean {
return this.length === other.length &&
ArrayUtilities.sequenceEquals(this.lineStarts(), other.lineStarts(), (v1, v2) => v1 === v2);
}
public lineStarts(): number[] {
if (this._lineStarts === null) {
this._lineStarts = this._computeLineStarts();
}
return this._lineStarts;
}
public lineCount(): number {
return this.lineStarts().length;
}
public getPosition(line: number, character: number): number {
return this.lineStarts()[line] + character;
}
public getLineNumberFromPosition(position: number): number {
if (position < 0 || position > this.length) {
throw Errors.argumentOutOfRange("position");
}
if (position === this.length) {
// this can happen when the user tried to get the line of items
// that are at the absolute end of this text (i.e. the EndOfLine
// token, or missing tokens that are at the end of the text).
// In this case, we want the last line in the text.
return this.lineCount() - 1;
}
// Binary search to find the right line
var lineNumber = ArrayUtilities.binarySearch(this.lineStarts(), position);
if (lineNumber < 0) {
lineNumber = (~lineNumber) - 1;
}
return lineNumber;
}
public getLineStartPosition(lineNumber: number): number {
return this.lineStarts()[lineNumber];
}
public fillLineAndCharacterFromPosition(position: number, lineAndCharacter: ILineAndCharacter): void {
if (position < 0 || position > this.length) {
throw Errors.argumentOutOfRange("position");
}
var lineNumber = this.getLineNumberFromPosition(position);
lineAndCharacter.line = lineNumber;
lineAndCharacter.character = position - this.lineStarts()[lineNumber];
}
public getLineAndCharacterFromPosition(position: number): LineAndCharacter {
if (position < 0 || position > this.length) {
throw Errors.argumentOutOfRange("position");
}
var lineNumber = this.getLineNumberFromPosition(position);
return new LineAndCharacter(lineNumber, position - this.lineStarts()[lineNumber]);
}
}
}
+35
View File
@@ -0,0 +1,35 @@
///<reference path='references.ts' />
module TypeScript {
export class LineAndCharacter {
private _line: number = 0;
private _character: number = 0;
/**
* Initializes a new instance of a LinePosition with the given line and character. ArgumentOutOfRangeException if "line" or "character" is less than zero.
* @param line The line of the line position. The first line in a file is defined as line 0 (zero based line numbering).
* @param character The character position in the line.
*/
constructor(line: number, character: number) {
if (line < 0) {
throw Errors.argumentOutOfRange("line");
}
if (character < 0) {
throw Errors.argumentOutOfRange("character");
}
this._line = line;
this._character = character;
}
public line(): number {
return this._line;
}
public character(): number {
return this._character;
}
}
}
+13
View File
@@ -0,0 +1,13 @@
///<reference path='references.ts' />
module TypeScript {
export class MathPrototype {
public static max(a: number, b: number): number {
return a >= b ? a : b;
}
public static min(a: number, b: number): number {
return a <= b ? a : b;
}
}
}
+13
View File
@@ -0,0 +1,13 @@
///<reference path='..\resources\references.ts' />
///<reference path='arrayUtilities.ts' />
///<reference path='debug.ts' />
///<reference path='diagnosticCategory.ts' />
///<reference path='diagnosticCore.ts' />
///<reference path='diagnosticInfo.ts' />
///<reference path='errors.ts' />
///<reference path='hash.ts' />
///<reference path='integerUtilities.ts' />
///<reference path='lineMap.ts' />
///<reference path='linePosition.ts' />
///<reference path='stringUtilities.ts' />
+159
View File
@@ -0,0 +1,159 @@
///<reference path='references.ts' />
module TypeScript.Collections {
export var DefaultStringTableCapacity = 256;
class StringTableEntry {
constructor(public Text: string,
public HashCode: number,
public Next: StringTableEntry) {
}
}
// A table of interned strings. Faster and better than an arbitrary hashtable for the needs of the
// scanner. Specifically, the scanner operates over a sliding window of characters, with a start
// and end pointer for the current lexeme. The scanner then wants to get the *interned* string
// represented by that subsection.
//
// Importantly, if the string is already interned, then it wants ask "is the string represented by
// this section of a char array contained within the table" in a non-allocating fashion. i.e. if
// you have "[' ', 'p', 'u', 'b', 'l', 'i', 'c', ' ']" and you ask to get the string represented by
// range [1, 7), then this table will return "public" without any allocations if that value was
// already in the table.
//
// Of course, if the value is not in the table then there will be an initial cost to allocate the
// string and the bucket for the table. However, that is only incurred the first time each unique
// string is added.
export class StringTable {
// TODO: uncomment this once typecheck bug is fixed.
private entries: StringTableEntry[];
private count: number = 0;
constructor(capacity: number) {
var size = Hash.getPrime(capacity);
this.entries = ArrayUtilities.createArray<StringTableEntry>(size, null);
}
public addCharArray(key: number[], start: number, len: number): string {
// Compute the hash for this key. Also ensure that it fits within 31 bits (so that it
// stays a non-heap integer, and so we can index into the array safely).
var hashCode = Hash.computeSimple31BitCharArrayHashCode(key, start, len) & 0x7FFFFFFF;
// Debug.assert(hashCode > 0);
// First see if we already have the string represented by "key[start, start + len)" already
// present in this table. If we do, just return that string. Do this without any
// allocations
var entry = this.findCharArrayEntry(key, start, len, hashCode);
if (entry !== null) {
return entry.Text;
}
// We don't have an entry for that string in our table. Convert that
var slice: number[] = key.slice(start, start + len);
return this.addEntry(StringUtilities.fromCharCodeArray(slice), hashCode);
}
private findCharArrayEntry(key: number[], start: number, len: number, hashCode: number) {
for (var e = this.entries[hashCode % this.entries.length]; e !== null; e = e.Next) {
if (e.HashCode === hashCode && StringTable.textCharArrayEquals(e.Text, key, start, len)) {
return e;
}
}
return null;
}
private addEntry(text: string, hashCode: number): string {
var index = hashCode % this.entries.length;
var e = new StringTableEntry(text, hashCode, this.entries[index]);
this.entries[index] = e;
// We grow when our load factor equals 1. I tried different load factors (like .75 and
// .5), however they seemed to have no effect on running time. With a load factor of 1
// we seem to get about 80% slot fill rate with an average of around 1.25 table entries
// per slot.
if (this.count === this.entries.length) {
this.grow();
}
this.count++;
return e.Text;
}
//private dumpStats() {
// var standardOut = Environment.standardOut;
// standardOut.WriteLine("----------------------")
// standardOut.WriteLine("String table stats");
// standardOut.WriteLine("Count : " + this.count);
// standardOut.WriteLine("Entries Length : " + this.entries.length);
// var longestSlot = 0;
// var occupiedSlots = 0;
// for (var i = 0; i < this.entries.length; i++) {
// if (this.entries[i] !== null) {
// occupiedSlots++;
// var current = this.entries[i];
// var slotCount = 0;
// while (current !== null) {
// slotCount++;
// current = current.Next;
// }
// longestSlot = MathPrototype.max(longestSlot, slotCount);
// }
// }
// standardOut.WriteLine("Occupied slots : " + occupiedSlots);
// standardOut.WriteLine("Longest slot : " + longestSlot);
// standardOut.WriteLine("Avg Length/Slot : " + (this.count / occupiedSlots));
// standardOut.WriteLine("----------------------");
//}
private grow(): void {
// this.dumpStats();
var newSize = Hash.expandPrime(this.entries.length);
var oldEntries = this.entries;
var newEntries: StringTableEntry[] = ArrayUtilities.createArray<StringTableEntry>(newSize, null);
this.entries = newEntries;
for (var i = 0; i < oldEntries.length; i++) {
var e = oldEntries[i];
while (e !== null) {
var newIndex = e.HashCode % newSize;
var tmp = e.Next;
e.Next = newEntries[newIndex];
newEntries[newIndex] = e;
e = tmp;
}
}
// this.dumpStats();
}
private static textCharArrayEquals(text: string, array: number[], start: number, length: number): boolean {
if (text.length !== length) {
return false;
}
var s = start;
for (var i = 0; i < length; i++) {
if (text.charCodeAt(i) !== array[s]) {
return false;
}
s++;
}
return true;
}
}
export var DefaultStringTable = new StringTable(DefaultStringTableCapacity);
}
+21
View File
@@ -0,0 +1,21 @@
///<reference path='references.ts' />
module TypeScript {
export class StringUtilities {
public static isString(value: any): boolean {
return Object.prototype.toString.apply(value, []) === '[object String]';
}
public static endsWith(string: string, value: string): boolean {
return string.substring(string.length - value.length, string.length) === value;
}
public static startsWith(string: string, value: string): boolean {
return string.substr(0, value.length) === value;
}
public static repeat(value: string, count: number) {
return Array(count + 1).join(value);
}
}
}
+52
View File
@@ -0,0 +1,52 @@
///<reference path='references.ts' />
var global: any = <any>Function("return this").call(null);
module TypeScript {
module Clock {
export var now: () => number;
export var resolution: number;
declare module WScript {
export function InitializeProjection(): void;
}
declare module TestUtilities {
export function QueryPerformanceCounter(): number;
export function QueryPerformanceFrequency(): number;
}
if (typeof WScript !== "undefined" && typeof global['WScript'].InitializeProjection !== "undefined") {
// Running in JSHost.
global['WScript'].InitializeProjection();
now = function () {
return TestUtilities.QueryPerformanceCounter();
};
resolution = TestUtilities.QueryPerformanceFrequency();
}
else {
now = function () {
return Date.now();
};
resolution = 1000;
}
}
export class Timer {
public startTime: number;
public time = 0;
public start() {
this.time = 0;
this.startTime = Clock.now();
}
public end() {
// Set time to MS.
this.time = (Clock.now() - this.startTime);
}
}
}
+152
View File
@@ -0,0 +1,152 @@
// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0.
// See LICENSE.txt in the project root for complete license information.
///<reference path='references.ts' />
module TypeScript.Services {
export class FindReferenceHelpers {
public static compareSymbolsForLexicalIdentity(firstSymbol: TypeScript.PullSymbol, secondSymbol: TypeScript.PullSymbol): boolean {
// Unwrap modules so that we're always referring to the variable.
if (!firstSymbol.isAlias() && firstSymbol.isContainer()) {
var containerForFirstSymbol = (<TypeScript.PullContainerSymbol>firstSymbol);
if (containerForFirstSymbol.getInstanceSymbol()) {
firstSymbol = containerForFirstSymbol.getInstanceSymbol();
}
}
if (!secondSymbol.isAlias() && secondSymbol.isContainer()) {
var containerForSecondSymbol = (<TypeScript.PullContainerSymbol>secondSymbol);
if (containerForSecondSymbol.getInstanceSymbol()) {
secondSymbol = containerForSecondSymbol.getInstanceSymbol();
}
}
if (firstSymbol.kind === secondSymbol.kind) {
if (firstSymbol === secondSymbol) {
return true;
}
// If we have two variables and they have the same name and the same parent, then
// they are the same symbol.
if (firstSymbol.kind === TypeScript.PullElementKind.Variable &&
firstSymbol.name === secondSymbol.name &&
firstSymbol.getDeclarations() && firstSymbol.getDeclarations().length >= 1 &&
secondSymbol.getDeclarations() && secondSymbol.getDeclarations().length >= 1) {
var firstSymbolDecl = firstSymbol.getDeclarations()[0];
var secondSymbolDecl = secondSymbol.getDeclarations()[0];
return firstSymbolDecl.getParentDecl() === secondSymbolDecl.getParentDecl();
}
// If we have two properties that belong to an object literal, then we need ot see
// if they came from teh same object literal ast.
if (firstSymbol.kind === TypeScript.PullElementKind.Property &&
firstSymbol.name === secondSymbol.name &&
firstSymbol.getDeclarations() && firstSymbol.getDeclarations().length >= 1 &&
secondSymbol.getDeclarations() && secondSymbol.getDeclarations().length >= 1) {
var firstSymbolDecl = firstSymbol.getDeclarations()[0];
var secondSymbolDecl = secondSymbol.getDeclarations()[0];
var firstParentDecl = firstSymbolDecl.getParentDecl();
var secondParentDecl = secondSymbolDecl.getParentDecl()
if (firstParentDecl.kind === TypeScript.PullElementKind.ObjectLiteral &&
secondParentDecl.kind === TypeScript.PullElementKind.ObjectLiteral) {
return firstParentDecl.ast() === secondParentDecl.ast();
}
}
// check if we are dealing with the implementation of interface method or a method override
if (firstSymbol.name === secondSymbol.name) {
// at this point firstSymbol.kind === secondSymbol.kind so we can pick any of those
switch (firstSymbol.kind) {
case PullElementKind.Property:
case PullElementKind.Method:
case PullElementKind.GetAccessor:
case PullElementKind.SetAccessor:
// these kinds can only be defined in types
var t1 = <PullTypeSymbol>firstSymbol.getContainer();
var t2 = <PullTypeSymbol>secondSymbol.getContainer();
t1._resolveDeclaredSymbol();
t2._resolveDeclaredSymbol();
return t1.hasBase(t2) || t2.hasBase(t1);
break;
}
}
return false;
}
else {
switch (firstSymbol.kind) {
case TypeScript.PullElementKind.Class: {
return this.checkSymbolsForDeclarationEquality(firstSymbol, secondSymbol);
}
case TypeScript.PullElementKind.Property: {
if (firstSymbol.isAccessor()) {
var getterSymbol = (<TypeScript.PullAccessorSymbol>firstSymbol).getGetter();
var setterSymbol = (<TypeScript.PullAccessorSymbol>firstSymbol).getSetter();
if (getterSymbol && getterSymbol === secondSymbol) {
return true;
}
if (setterSymbol && setterSymbol === secondSymbol) {
return true;
}
}
return false;
}
case TypeScript.PullElementKind.Function: {
if (secondSymbol.isAccessor()) {
var getterSymbol = (<TypeScript.PullAccessorSymbol>secondSymbol).getGetter();
var setterSymbol = (<TypeScript.PullAccessorSymbol>secondSymbol).getSetter();
if (getterSymbol && getterSymbol === firstSymbol) {
return true;
}
if (setterSymbol && setterSymbol === firstSymbol) {
return true;
}
}
return false;
}
case TypeScript.PullElementKind.ConstructorMethod: {
return this.checkSymbolsForDeclarationEquality(firstSymbol, secondSymbol);
}
}
}
return firstSymbol === secondSymbol;
}
private static checkSymbolsForDeclarationEquality(firstSymbol: TypeScript.PullSymbol, secondSymbol: TypeScript.PullSymbol): boolean {
var firstSymbolDeclarations: TypeScript.PullDecl[] = firstSymbol.getDeclarations();
var secondSymbolDeclarations: TypeScript.PullDecl[] = secondSymbol.getDeclarations();
for (var i = 0, iLen = firstSymbolDeclarations.length; i < iLen; i++) {
for (var j = 0, jLen = secondSymbolDeclarations.length; j < jLen; j++) {
if (this.declarationsAreSameOrParents(firstSymbolDeclarations[i], secondSymbolDeclarations[j])) {
return true;
}
}
}
return false;
}
private static declarationsAreSameOrParents(firstDecl: TypeScript.PullDecl, secondDecl: TypeScript.PullDecl): boolean {
var firstParent: TypeScript.PullDecl = firstDecl.getParentDecl();
var secondParent: TypeScript.PullDecl = secondDecl.getParentDecl();
if (firstDecl === secondDecl ||
firstDecl === secondParent ||
firstParent === secondDecl ||
firstParent === secondParent) {
return true;
}
return false;
}
}
}
+320
View File
@@ -0,0 +1,320 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class Formatter extends MultipleTokenIndenter {
private previousTokenSpan: TokenSpan = null;
private previousTokenParent: IndentationNodeContext = null;
// TODO: implement it with skipped tokens in Fidelity
private scriptHasErrors: boolean = false;
private rulesProvider: RulesProvider;
private formattingRequestKind: FormattingRequestKind;
private formattingContext: FormattingContext;
constructor(textSpan: TextSpan,
sourceUnit: SourceUnitSyntax,
indentFirstToken: boolean,
options: FormattingOptions,
snapshot: ITextSnapshot,
rulesProvider: RulesProvider,
formattingRequestKind: FormattingRequestKind) {
super(textSpan, sourceUnit, snapshot, indentFirstToken, options);
this.previousTokenParent = this.parent().clone(this.indentationNodeContextPool());
this.rulesProvider = rulesProvider;
this.formattingRequestKind = formattingRequestKind;
this.formattingContext = new FormattingContext(this.snapshot(), this.formattingRequestKind);
}
public static getEdits(textSpan: TextSpan,
sourceUnit: SourceUnitSyntax,
options: FormattingOptions,
indentFirstToken: boolean,
snapshot: ITextSnapshot,
rulesProvider: RulesProvider,
formattingRequestKind: FormattingRequestKind): TextEditInfo[] {
var walker = new Formatter(textSpan, sourceUnit, indentFirstToken, options, snapshot, rulesProvider, formattingRequestKind);
visitNodeOrToken(walker, sourceUnit);
return walker.edits();
}
public visitTokenInSpan(token: ISyntaxToken): void {
if (token.fullWidth() !== 0) {
var tokenSpan = new TextSpan(this.position() + token.leadingTriviaWidth(), width(token));
if (this.textSpan().containsTextSpan(tokenSpan)) {
this.processToken(token);
}
}
// Call the base class to process the token and indent it if needed
super.visitTokenInSpan(token);
}
private processToken(token: ISyntaxToken): void {
var position = this.position();
// Extract any leading comments
if (token.leadingTriviaWidth() !== 0) {
this.processTrivia(token.leadingTrivia(), position);
position += token.leadingTriviaWidth();
}
// Push the token
var currentTokenSpan = new TokenSpan(token.kind(), position, width(token));
if (!this.parent().hasSkippedOrMissingTokenChild()) {
if (this.previousTokenSpan) {
// Note that formatPair calls TrimWhitespaceInLineRange in between the 2 tokens
this.formatPair(this.previousTokenSpan, this.previousTokenParent, currentTokenSpan, this.parent());
}
else {
// We still want to trim whitespace even if it is the first trivia of the first token. Trim from the beginning of the span to the trivia
this.trimWhitespaceInLineRange(this.getLineNumber(this.textSpan()), this.getLineNumber(currentTokenSpan));
}
}
this.previousTokenSpan = currentTokenSpan;
if (this.previousTokenParent) {
// Make sure to clear the previous parent before assigning a new value to it
this.indentationNodeContextPool().releaseNode(this.previousTokenParent, /* recursive */true);
}
this.previousTokenParent = this.parent().clone(this.indentationNodeContextPool());
position += width(token);
// Extract any trailing comments
if (token.trailingTriviaWidth() !== 0) {
this.processTrivia(token.trailingTrivia(), position);
}
}
private processTrivia(triviaList: ISyntaxTriviaList, fullStart: number) {
var position = fullStart;
for (var i = 0, n = triviaList.count(); i < n ; i++) {
var trivia = triviaList.syntaxTriviaAt(i);
// For a comment, format it like it is a token. For skipped text, eat it up as a token, but skip the formatting
if (trivia.isComment() || trivia.isSkippedToken()) {
var currentTokenSpan = new TokenSpan(trivia.kind(), position, trivia.fullWidth());
if (this.textSpan().containsTextSpan(currentTokenSpan)) {
if (trivia.isComment() && this.previousTokenSpan) {
// Note that formatPair calls TrimWhitespaceInLineRange in between the 2 tokens
this.formatPair(this.previousTokenSpan, this.previousTokenParent, currentTokenSpan, this.parent());
}
else {
// We still want to trim whitespace even if it is the first trivia of the first token. Trim from the beginning of the span to the trivia
var startLine = this.getLineNumber(this.previousTokenSpan || this.textSpan());
this.trimWhitespaceInLineRange(startLine, this.getLineNumber(currentTokenSpan));
}
this.previousTokenSpan = currentTokenSpan;
if (this.previousTokenParent) {
// Make sure to clear the previous parent before assigning a new value to it
this.indentationNodeContextPool().releaseNode(this.previousTokenParent, /* recursive */true);
}
this.previousTokenParent = this.parent().clone(this.indentationNodeContextPool());
}
}
position += trivia.fullWidth();
}
}
private findCommonParents(parent1: IndentationNodeContext, parent2: IndentationNodeContext): IndentationNodeContext {
// TODO: disable debug assert message
var shallowParent: IndentationNodeContext;
var shallowParentDepth: number;
var deepParent: IndentationNodeContext;
var deepParentDepth: number;
if (parent1.depth() < parent2.depth()) {
shallowParent = parent1;
shallowParentDepth = parent1.depth();
deepParent = parent2;
deepParentDepth = parent2.depth();
}
else {
shallowParent = parent2;
shallowParentDepth = parent2.depth();
deepParent = parent1;
deepParentDepth = parent1.depth();
}
Debug.assert(shallowParentDepth >= 0, "Expected shallowParentDepth >= 0");
Debug.assert(deepParentDepth >= 0, "Expected deepParentDepth >= 0");
Debug.assert(deepParentDepth >= shallowParentDepth, "Expected deepParentDepth >= shallowParentDepth");
while (deepParentDepth > shallowParentDepth) {
deepParent = <IndentationNodeContext>deepParent.parent();
deepParentDepth--;
}
Debug.assert(deepParentDepth === shallowParentDepth, "Expected deepParentDepth === shallowParentDepth");
while (deepParent.node() && shallowParent.node()) {
if (deepParent.node() === shallowParent.node()) {
return deepParent;
}
deepParent = <IndentationNodeContext>deepParent.parent();
shallowParent = <IndentationNodeContext>shallowParent.parent();
}
// The root should be the first element in the parent chain, we can not be here unless something wrong
// happened along the way
throw Errors.invalidOperation();
}
private formatPair(t1: TokenSpan, t1Parent: IndentationNodeContext, t2: TokenSpan, t2Parent: IndentationNodeContext): void {
var token1Line = this.getLineNumber(t1);
var token2Line = this.getLineNumber(t2);
// Find common parent
var commonParent= this.findCommonParents(t1Parent, t2Parent);
// Update the context
this.formattingContext.updateContext(t1, t1Parent, t2, t2Parent, commonParent);
// Find rules matching the current context
var rule = this.rulesProvider.getRulesMap().GetRule(this.formattingContext);
if (rule != null) {
// Record edits from the rule
this.RecordRuleEdits(rule, t1, t2);
// Handle the case where the next line is moved to be the end of this line.
// In this case we don't indent the next line in the next pass.
if ((rule.Operation.Action == RuleAction.Space || rule.Operation.Action == RuleAction.Delete) &&
token1Line != token2Line) {
this.forceSkipIndentingNextToken(t2.start());
}
// Handle the case where token2 is moved to the new line.
// In this case we indent token2 in the next pass but we set
// sameLineIndent flag to notify the indenter that the indentation is within the line.
if (rule.Operation.Action == RuleAction.NewLine && token1Line == token2Line) {
this.forceIndentNextToken(t2.start());
}
}
// We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line
if (token1Line != token2Line && (!rule || (rule.Operation.Action != RuleAction.Delete && rule.Flag != RuleFlags.CanDeleteNewLines))) {
this.trimWhitespaceInLineRange(token1Line, token2Line, t1);
}
}
private getLineNumber(span: TextSpan): number {
return this.snapshot().getLineNumberFromPosition(span.start());
}
private trimWhitespaceInLineRange(startLine: number, endLine: number, token?: TokenSpan): void {
for (var lineNumber = startLine; lineNumber < endLine; ++lineNumber) {
var line = this.snapshot().getLineFromLineNumber(lineNumber);
this.trimWhitespace(line, token);
}
}
private trimWhitespace(line: ITextSnapshotLine, token?: TokenSpan): void {
// Don't remove the trailing spaces inside comments (this includes line comments and block comments)
if (token && (token.kind == SyntaxKind.MultiLineCommentTrivia || token.kind == SyntaxKind.SingleLineCommentTrivia) && token.start() <= line.endPosition() && token.end() >= line.endPosition())
return;
var text = line.getText();
var index = 0;
for (index = text.length - 1; index >= 0; --index) {
if (!CharacterInfo.isWhitespace(text.charCodeAt(index))) {
break;
}
}
++index;
if (index < text.length) {
this.recordEdit(line.startPosition() + index, line.length() - index, "");
}
}
private RecordRuleEdits(rule: Rule, t1: TokenSpan, t2: TokenSpan): void {
if (rule.Operation.Action == RuleAction.Ignore) {
return;
}
var betweenSpan: TextSpan;
switch (rule.Operation.Action) {
case RuleAction.Delete:
{
betweenSpan = new TextSpan(t1.end(), t2.start() - t1.end());
if (betweenSpan.length() > 0) {
this.recordEdit(betweenSpan.start(), betweenSpan.length(), "");
return;
}
}
break;
case RuleAction.NewLine:
{
if (!(rule.Flag == RuleFlags.CanDeleteNewLines || this.getLineNumber(t1) == this.getLineNumber(t2))) {
return;
}
betweenSpan = new TextSpan(t1.end(), t2.start() - t1.end());
var doEdit = false;
var betweenText = this.snapshot().getText(betweenSpan);
var lineFeedLoc = betweenText.indexOf(this.options.newLineCharacter);
if (lineFeedLoc < 0) {
// no linefeeds, do the edit
doEdit = true;
}
else {
// We only require one line feed. If there is another one, do the edit
lineFeedLoc = betweenText.indexOf(this.options.newLineCharacter, lineFeedLoc + 1);
if (lineFeedLoc >= 0) {
doEdit = true;
}
}
if (doEdit) {
this.recordEdit(betweenSpan.start(), betweenSpan.length(), this.options.newLineCharacter);
return;
}
}
break;
case RuleAction.Space:
{
if (!(rule.Flag == RuleFlags.CanDeleteNewLines || this.getLineNumber(t1) == this.getLineNumber(t2))) {
return;
}
betweenSpan = new TextSpan(t1.end(), t2.start() - t1.end());
if (betweenSpan.length() > 1 || this.snapshot().getText(betweenSpan) != " ") {
this.recordEdit(betweenSpan.start(), betweenSpan.length(), " ");
return;
}
}
break;
}
}
}
}
+40
View File
@@ -0,0 +1,40 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='..\services.ts' />
///<reference path='textSnapshot.ts' />
///<reference path='textSnapshotLine.ts' />
///<reference path='snapshotPoint.ts' />
///<reference path='formattingContext.ts' />
///<reference path='formattingManager.ts' />
///<reference path='formattingRequestKind.ts' />
///<reference path='rule.ts' />
///<reference path='ruleAction.ts' />
///<reference path='ruleDescriptor.ts' />
///<reference path='ruleFlag.ts' />
///<reference path='ruleOperation.ts' />
///<reference path='ruleOperationContext.ts' />
///<reference path='rules.ts' />
///<reference path='rulesMap.ts' />
///<reference path='rulesProvider.ts' />
///<reference path='textEditInfo.ts' />
///<reference path='tokenRange.ts' />
///<reference path='tokenSpan.ts' />
///<reference path='indentationNodeContext.ts' />
///<reference path='indentationNodeContextPool.ts' />
///<reference path='indentationTrackingWalker.ts' />
///<reference path='multipleTokenIndenter.ts' />
///<reference path='singleTokenIndenter.ts' />
///<reference path='formatter.ts' />
@@ -0,0 +1,116 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
/// <reference path="formatting.ts"/>
module TypeScript.Services.Formatting {
export class FormattingContext {
public currentTokenSpan: TokenSpan = null;
public nextTokenSpan: TokenSpan = null;
public contextNode: IndentationNodeContext = null;
public currentTokenParent: IndentationNodeContext = null;
public nextTokenParent: IndentationNodeContext = null;
private contextNodeAllOnSameLine: boolean = null;
private nextNodeAllOnSameLine: boolean = null;
private tokensAreOnSameLine: boolean = null;
private contextNodeBlockIsOnOneLine: boolean = null;
private nextNodeBlockIsOnOneLine: boolean = null;
constructor(private snapshot: ITextSnapshot, public formattingRequestKind: FormattingRequestKind) {
Debug.assert(this.snapshot != null, "snapshot is null");
}
public updateContext(currentTokenSpan: TokenSpan, currentTokenParent: IndentationNodeContext, nextTokenSpan: TokenSpan, nextTokenParent: IndentationNodeContext, commonParent: IndentationNodeContext) {
Debug.assert(currentTokenSpan != null, "currentTokenSpan is null");
Debug.assert(currentTokenParent != null, "currentTokenParent is null");
Debug.assert(nextTokenSpan != null, "nextTokenSpan is null");
Debug.assert(nextTokenParent != null, "nextTokenParent is null");
Debug.assert(commonParent != null, "commonParent is null");
this.currentTokenSpan = currentTokenSpan;
this.currentTokenParent = currentTokenParent;
this.nextTokenSpan = nextTokenSpan;
this.nextTokenParent = nextTokenParent;
this.contextNode = commonParent;
this.contextNodeAllOnSameLine = null;
this.nextNodeAllOnSameLine = null;
this.tokensAreOnSameLine = null;
this.contextNodeBlockIsOnOneLine = null;
this.nextNodeBlockIsOnOneLine = null;
}
public ContextNodeAllOnSameLine(): boolean {
if (this.contextNodeAllOnSameLine === null) {
this.contextNodeAllOnSameLine = this.NodeIsOnOneLine(this.contextNode);
}
return this.contextNodeAllOnSameLine;
}
public NextNodeAllOnSameLine(): boolean {
if (this.nextNodeAllOnSameLine === null) {
this.nextNodeAllOnSameLine = this.NodeIsOnOneLine(this.nextTokenParent);
}
return this.nextNodeAllOnSameLine;
}
public TokensAreOnSameLine(): boolean {
if (this.tokensAreOnSameLine === null) {
var startLine = this.snapshot.getLineNumberFromPosition(this.currentTokenSpan.start());
var endLine = this.snapshot.getLineNumberFromPosition(this.nextTokenSpan.start());
this.tokensAreOnSameLine = (startLine == endLine);
}
return this.tokensAreOnSameLine;
}
public ContextNodeBlockIsOnOneLine() {
if (this.contextNodeBlockIsOnOneLine === null) {
this.contextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.contextNode);
}
return this.contextNodeBlockIsOnOneLine;
}
public NextNodeBlockIsOnOneLine() {
if (this.nextNodeBlockIsOnOneLine === null) {
this.nextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.nextTokenParent);
}
return this.nextNodeBlockIsOnOneLine;
}
public NodeIsOnOneLine(node: IndentationNodeContext): boolean {
var startLine = this.snapshot.getLineNumberFromPosition(node.start());
var endLine = this.snapshot.getLineNumberFromPosition(node.end());
return startLine == endLine;
}
// Now we know we have a block (or a fake block represented by some other kind of node with an open and close brace as children).
// IMPORTANT!!! This relies on the invariant that IsBlockContext must return true ONLY for nodes with open and close braces as immediate children
public BlockIsOnOneLine(node: IndentationNodeContext): boolean {
var block = <BlockSyntax>node.node();
// Now check if they are on the same line
return this.snapshot.getLineNumberFromPosition(end(block.openBraceToken)) ===
this.snapshot.getLineNumberFromPosition(start(block.closeBraceToken));
}
}
}
@@ -0,0 +1,128 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
/// <reference path="formatting.ts"/>
module TypeScript.Services.Formatting {
export class FormattingManager {
private options: FormattingOptions;
constructor(private syntaxTree: SyntaxTree, private snapshot: ITextSnapshot, private rulesProvider: RulesProvider, editorOptions: ts.EditorOptions) {
//
// TODO: convert to use FormattingOptions instead of EditorOptions
this.options = new FormattingOptions(!editorOptions.ConvertTabsToSpaces, editorOptions.TabSize, editorOptions.IndentSize, editorOptions.NewLineCharacter)
}
public formatSelection(minChar: number, limChar: number): ts.TextEdit[] {
var span = TextSpan.fromBounds(minChar, limChar);
return this.formatSpan(span, FormattingRequestKind.FormatSelection);
}
public formatDocument(minChar: number, limChar: number): ts.TextEdit[] {
var span = TextSpan.fromBounds(minChar, limChar);
return this.formatSpan(span, FormattingRequestKind.FormatDocument);
}
public formatOnPaste(minChar: number, limChar: number): ts.TextEdit[] {
var span = TextSpan.fromBounds(minChar, limChar);
return this.formatSpan(span, FormattingRequestKind.FormatOnPaste);
}
public formatOnSemicolon(caretPosition: number): ts.TextEdit[] {
var sourceUnit = this.syntaxTree.sourceUnit();
var semicolonPositionedToken = findToken(sourceUnit, caretPosition - 1);
if (semicolonPositionedToken.kind() === SyntaxKind.SemicolonToken) {
// Find the outer most parent that this semicolon terminates
var current: ISyntaxElement = semicolonPositionedToken;
while (current.parent !== null &&
end(current.parent) === end(semicolonPositionedToken) &&
current.parent.kind() !== SyntaxKind.List) {
current = current.parent;
}
// Compute the span
var span = new TextSpan(fullStart(current), fullWidth(current));
// Format the span
return this.formatSpan(span, FormattingRequestKind.FormatOnSemicolon);
}
return [];
}
public formatOnClosingCurlyBrace(caretPosition: number): ts.TextEdit[] {
var sourceUnit = this.syntaxTree.sourceUnit();
var closeBracePositionedToken = findToken(sourceUnit, caretPosition - 1);
if (closeBracePositionedToken.kind() === SyntaxKind.CloseBraceToken) {
// Find the outer most parent that this closing brace terminates
var current: ISyntaxElement = closeBracePositionedToken;
while (current.parent !== null &&
end(current.parent) === end(closeBracePositionedToken) &&
current.parent.kind() !== SyntaxKind.List) {
current = current.parent;
}
// Compute the span
var span = new TextSpan(fullStart(current), fullWidth(current));
// Format the span
return this.formatSpan(span, FormattingRequestKind.FormatOnClosingCurlyBrace);
}
return [];
}
public formatOnEnter(caretPosition: number): ts.TextEdit[] {
var lineNumber = this.snapshot.getLineNumberFromPosition(caretPosition);
if (lineNumber > 0) {
// Format both lines
var prevLine = this.snapshot.getLineFromLineNumber(lineNumber - 1);
var currentLine = this.snapshot.getLineFromLineNumber(lineNumber);
var span = TextSpan.fromBounds(prevLine.startPosition(), currentLine.endPosition());
// Format the span
return this.formatSpan(span, FormattingRequestKind.FormatOnEnter);
}
return [];
}
private formatSpan(span: TextSpan, formattingRequestKind: FormattingRequestKind): ts.TextEdit[] {
// Always format from the beginning of the line
var startLine = this.snapshot.getLineFromPosition(span.start());
span = TextSpan.fromBounds(startLine.startPosition(), span.end());
var result: ts.TextEdit[] = [];
var formattingEdits = Formatter.getEdits(span, this.syntaxTree.sourceUnit(), this.options, true, this.snapshot, this.rulesProvider, formattingRequestKind);
//
// TODO: Change the ILanguageService interface to return TextEditInfo (with start, and length) instead of TextEdit (with minChar and limChar)
formattingEdits.forEach((item) => {
result.push({
minChar: item.position,
limChar: item.position + item.length,
text: item.replaceWith
});
});
return result;
}
}
}
@@ -0,0 +1,27 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
/// <reference path="formatting.ts"/>
module TypeScript.Services.Formatting {
export enum FormattingRequestKind {
FormatDocument,
FormatSelection,
FormatOnEnter,
FormatOnSemicolon,
FormatOnClosingCurlyBrace,
FormatOnPaste
}
}
@@ -0,0 +1,103 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class IndentationNodeContext {
private _node: ISyntaxNode;
private _parent: IndentationNodeContext;
private _fullStart: number;
private _indentationAmount: number;
private _childIndentationAmountDelta: number;
private _depth: number;
private _hasSkippedOrMissingTokenChild: boolean;
constructor(parent: IndentationNodeContext, node: ISyntaxNode, fullStart: number, indentationAmount: number, childIndentationAmountDelta: number) {
this.update(parent, node, fullStart, indentationAmount, childIndentationAmountDelta);
}
public parent(): IndentationNodeContext {
return this._parent;
}
public node(): ISyntaxNode {
return this._node;
}
public fullStart(): number {
return this._fullStart;
}
public fullWidth(): number {
return fullWidth(this._node);
}
public start(): number {
return this._fullStart + leadingTriviaWidth(this._node);
}
public end(): number {
return this._fullStart + leadingTriviaWidth(this._node) + width(this._node);
}
public indentationAmount(): number {
return this._indentationAmount;
}
public childIndentationAmountDelta(): number {
return this._childIndentationAmountDelta;
}
public depth(): number {
return this._depth;
}
public kind(): SyntaxKind {
return this._node.kind();
}
public hasSkippedOrMissingTokenChild(): boolean {
if (this._hasSkippedOrMissingTokenChild === null) {
this._hasSkippedOrMissingTokenChild = Syntax.nodeHasSkippedOrMissingTokens(this._node);
}
return this._hasSkippedOrMissingTokenChild;
}
public clone(pool: IndentationNodeContextPool): IndentationNodeContext {
var parent: IndentationNodeContext = null;
if (this._parent) {
parent = this._parent.clone(pool);
}
return pool.getNode(parent, this._node, this._fullStart, this._indentationAmount, this._childIndentationAmountDelta);
}
public update(parent: IndentationNodeContext, node: ISyntaxNode, fullStart: number, indentationAmount: number, childIndentationAmountDelta: number) {
this._parent = parent;
this._node = node;
this._fullStart = fullStart;
this._indentationAmount = indentationAmount;
this._childIndentationAmountDelta = childIndentationAmountDelta;
this._hasSkippedOrMissingTokenChild = null;
if (parent) {
this._depth = parent.depth() + 1;
}
else {
this._depth = 0;
}
}
}
}
@@ -0,0 +1,43 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class IndentationNodeContextPool {
private nodes: IndentationNodeContext[] = [];
public getNode(parent: IndentationNodeContext, node: ISyntaxNode, fullStart: number, indentationLevel: number, childIndentationLevelDelta: number): IndentationNodeContext {
if (this.nodes.length > 0) {
var cachedNode = this.nodes.pop();
cachedNode.update(parent, node, fullStart, indentationLevel, childIndentationLevelDelta);
return cachedNode;
}
return new IndentationNodeContext(parent, node, fullStart, indentationLevel, childIndentationLevelDelta);
}
public releaseNode(node: IndentationNodeContext, recursive: boolean = false): void {
this.nodes.push(node);
if (recursive) {
var parent = node.parent();
if (parent) {
this.releaseNode(parent, recursive);
}
}
}
}
}
@@ -0,0 +1,349 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class IndentationTrackingWalker extends SyntaxWalker {
private _position: number = 0;
private _parent: IndentationNodeContext = null;
private _textSpan: TextSpan;
private _snapshot: ITextSnapshot;
private _lastTriviaWasNewLine: boolean;
private _indentationNodeContextPool: IndentationNodeContextPool;
private _text: ISimpleText;
constructor(textSpan: TextSpan, sourceUnit: SourceUnitSyntax, snapshot: ITextSnapshot, indentFirstToken: boolean, public options: FormattingOptions) {
super();
// Create a pool object to manage context nodes while walking the tree
this._indentationNodeContextPool = new IndentationNodeContextPool();
this._textSpan = textSpan;
this._text = sourceUnit.syntaxTree.text;
this._snapshot = snapshot;
this._parent = this._indentationNodeContextPool.getNode(null, sourceUnit, 0, 0, 0);
// Is the first token in the span at the start of a new line.
this._lastTriviaWasNewLine = indentFirstToken;
}
public position(): number {
return this._position;
}
public parent(): IndentationNodeContext {
return this._parent;
}
public textSpan(): TextSpan {
return this._textSpan;
}
public snapshot(): ITextSnapshot {
return this._snapshot;
}
public indentationNodeContextPool(): IndentationNodeContextPool {
return this._indentationNodeContextPool;
}
public forceIndentNextToken(tokenStart: number): void {
this._lastTriviaWasNewLine = true;
this.forceRecomputeIndentationOfParent(tokenStart, true);
}
public forceSkipIndentingNextToken(tokenStart: number): void {
this._lastTriviaWasNewLine = false;
this.forceRecomputeIndentationOfParent(tokenStart, false);
}
public indentToken(token: ISyntaxToken, indentationAmount: number, commentIndentationAmount: number): void {
throw Errors.abstract();
}
public visitTokenInSpan(token: ISyntaxToken): void {
if (this._lastTriviaWasNewLine) {
// Compute the indentation level at the current token
var indentationAmount = this.getTokenIndentationAmount(token);
var commentIndentationAmount = this.getCommentIndentationAmount(token);
// Process the token
this.indentToken(token, indentationAmount, commentIndentationAmount);
}
}
public visitToken(token: ISyntaxToken): void {
var tokenSpan = new TextSpan(this._position, token.fullWidth());
if (tokenSpan.intersectsWithTextSpan(this._textSpan)) {
this.visitTokenInSpan(token);
// Only track new lines on tokens within the range. Make sure to check that the last trivia is a newline, and not just one of the trivia
var trivia = token.trailingTrivia();
this._lastTriviaWasNewLine = trivia.hasNewLine() && trivia.syntaxTriviaAt(trivia.count() - 1).kind() == SyntaxKind.NewLineTrivia;
}
// Update the position
this._position += token.fullWidth();
}
public visitNode(node: ISyntaxNode): void {
var nodeSpan = new TextSpan(this._position, fullWidth(node));
if (nodeSpan.intersectsWithTextSpan(this._textSpan)) {
// Update indentation level
var indentation = this.getNodeIndentation(node);
// Update the parent
var currentParent = this._parent;
this._parent = this._indentationNodeContextPool.getNode(currentParent, node, this._position, indentation.indentationAmount, indentation.indentationAmountDelta);
// Visit node
visitNodeOrToken(this, node);
// Reset state
this._indentationNodeContextPool.releaseNode(this._parent);
this._parent = currentParent;
}
else {
// We're skipping the node, so update our position accordingly.
this._position += fullWidth(node);
}
}
private getTokenIndentationAmount(token: ISyntaxToken): number {
// If this is the first token of a node, it should follow the node indentation and not the child indentation;
// (e.g.class in a class declaration or module in module declariotion).
// Open and close braces should follow the indentation of thier parent as well(e.g.
// class {
// }
// Also in a do-while statement, the while should be indented like the parent.
if (firstToken(this._parent.node()) === token ||
token.kind() === SyntaxKind.OpenBraceToken || token.kind() === SyntaxKind.CloseBraceToken ||
token.kind() === SyntaxKind.OpenBracketToken || token.kind() === SyntaxKind.CloseBracketToken ||
(token.kind() === SyntaxKind.WhileKeyword && this._parent.node().kind() == SyntaxKind.DoStatement)) {
return this._parent.indentationAmount();
}
return (this._parent.indentationAmount() + this._parent.childIndentationAmountDelta());
}
private getCommentIndentationAmount(token: ISyntaxToken): number {
// If this is token terminating an indentation scope, leading comments should be indented to follow the children
// indentation level and not the node
if (token.kind() === SyntaxKind.CloseBraceToken || token.kind() === SyntaxKind.CloseBracketToken) {
return (this._parent.indentationAmount() + this._parent.childIndentationAmountDelta());
}
return this._parent.indentationAmount();
}
private getNodeIndentation(node: ISyntaxNode, newLineInsertedByFormatting?: boolean): { indentationAmount: number; indentationAmountDelta: number; } {
var parent = this._parent;
// We need to get the parent's indentation, which could be one of 2 things. If first token of the parent is in the span, use the parent's computed indentation.
// If the parent was outside the span, use the actual indentation of the parent.
var parentIndentationAmount: number;
if (this._textSpan.containsPosition(parent.start())) {
parentIndentationAmount = parent.indentationAmount();
}
else {
if (parent.kind() === SyntaxKind.Block && !this.shouldIndentBlockInParent(this._parent.parent())) {
// Blocks preserve the indentation of their containing node (unless they're a
// standalone block in a list). i.e. if you have:
//
// function foo(
// a: number) {
//
// Then we expect the indentation of the block to be tied to the function, not to
// the line that the block is defined on. If we were to do the latter, then the
// indentation would be here:
//
// function foo(
// a: number) {
// |
//
// Instead of:
//
// function foo(
// a: number) {
// |
parent = this._parent.parent();
}
var line = this._snapshot.getLineFromPosition(parent.start()).getText();
var firstNonWhiteSpacePosition = Indentation.firstNonWhitespacePosition(line);
parentIndentationAmount = Indentation.columnForPositionInString(line, firstNonWhiteSpacePosition, this.options);
}
var parentIndentationAmountDelta = parent.childIndentationAmountDelta();
// The indentation level of the node
var indentationAmount: number;
// The delta it adds to its children.
var indentationAmountDelta: number;
var parentNode = parent.node();
switch (node.kind()) {
default:
// General case
// This node should follow the child indentation set by its parent
// This node does not introduce any new indentation scope, indent any decendants of this node (tokens or child nodes)
// using the same indentation level
indentationAmount = (parentIndentationAmount + parentIndentationAmountDelta);
indentationAmountDelta = 0;
break;
// Statements introducing {}
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.ObjectType:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.SwitchStatement:
case SyntaxKind.ObjectLiteralExpression:
case SyntaxKind.ConstructorDeclaration:
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.MemberFunctionDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.IndexMemberDeclaration:
case SyntaxKind.CatchClause:
// Statements introducing []
case SyntaxKind.ArrayLiteralExpression:
case SyntaxKind.ArrayType:
case SyntaxKind.ElementAccessExpression:
case SyntaxKind.IndexSignature:
// Other statements
case SyntaxKind.ForStatement:
case SyntaxKind.ForInStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.WithStatement:
case SyntaxKind.CaseSwitchClause:
case SyntaxKind.DefaultSwitchClause:
case SyntaxKind.ReturnStatement:
case SyntaxKind.ThrowStatement:
case SyntaxKind.SimpleArrowFunctionExpression:
case SyntaxKind.ParenthesizedArrowFunctionExpression:
case SyntaxKind.VariableDeclaration:
case SyntaxKind.ExportAssignment:
// Expressions which have argument lists or parameter lists
case SyntaxKind.InvocationExpression:
case SyntaxKind.ObjectCreationExpression:
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
// These nodes should follow the child indentation set by its parent;
// they introduce a new indenation scope; children should be indented at one level deeper
indentationAmount = (parentIndentationAmount + parentIndentationAmountDelta);
indentationAmountDelta = this.options.indentSpaces;
break;
case SyntaxKind.IfStatement:
if (parent.kind() === SyntaxKind.ElseClause &&
!SyntaxUtilities.isLastTokenOnLine((<ElseClauseSyntax>parentNode).elseKeyword, this._text)) {
// This is an else if statement with the if on the same line as the else, do not indent the if statmement.
// Note: Children indentation has already been set by the parent if statement, so no need to increment
indentationAmount = parentIndentationAmount;
}
else {
// Otherwise introduce a new indenation scope; children should be indented at one level deeper
indentationAmount = (parentIndentationAmount + parentIndentationAmountDelta);
}
indentationAmountDelta = this.options.indentSpaces;
break;
case SyntaxKind.ElseClause:
// Else should always follow its parent if statement indentation.
// Note: Children indentation has already been set by the parent if statement, so no need to increment
indentationAmount = parentIndentationAmount;
indentationAmountDelta = this.options.indentSpaces;
break;
case SyntaxKind.Block:
// Check if the block is a member in a list of statements (if the parent is a source unit, module, or block, or switch clause)
if (this.shouldIndentBlockInParent(parent)) {
indentationAmount = parentIndentationAmount + parentIndentationAmountDelta;
}
else {
indentationAmount = parentIndentationAmount;
}
indentationAmountDelta = this.options.indentSpaces;
break;
}
// If the parent happens to start on the same line as this node, then override the current node indenation with that
// of the parent. This avoid having to add an extra level of indentation for the children. e.g.:
// return {
// a:1
// };
// instead of:
// return {
// a:1
// };
// We also need to pass the delta (if it is nonzero) to the children, so that subsequent lines get indented. Essentially, if any node starting on the given line
// has a nonzero delta , the resulting delta should be inherited from this node. This is to indent cases like the following:
// return a
// || b;
// Lastly, it is possible the node indentation needs to be recomputed because the formatter inserted a newline before its first token.
// If this is the case, we know the node no longer starts on the same line as its parent (or at least we shouldn't treat it as such).
if (parentNode) {
if (!newLineInsertedByFormatting /*This could be false or undefined here*/) {
var parentStartLine = this._snapshot.getLineNumberFromPosition(parent.start());
var currentNodeStartLine = this._snapshot.getLineNumberFromPosition(this._position + leadingTriviaWidth(node));
if (parentStartLine === currentNodeStartLine || newLineInsertedByFormatting === false /*meaning a new line was removed and we are force recomputing*/) {
indentationAmount = parentIndentationAmount;
indentationAmountDelta = Math.min(this.options.indentSpaces, parentIndentationAmountDelta + indentationAmountDelta);
}
}
}
return {
indentationAmount: indentationAmount,
indentationAmountDelta: indentationAmountDelta
};
}
private shouldIndentBlockInParent(parent: IndentationNodeContext): boolean {
switch (parent.kind()) {
case SyntaxKind.SourceUnit:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.Block:
case SyntaxKind.CaseSwitchClause:
case SyntaxKind.DefaultSwitchClause:
return true;
default:
return false;
}
}
private forceRecomputeIndentationOfParent(tokenStart: number, newLineAdded: boolean /*as opposed to removed*/): void {
var parent = this._parent;
if (parent.fullStart() === tokenStart) {
// Temporarily pop the parent before recomputing
this._parent = parent.parent();
var indentation = this.getNodeIndentation(parent.node(), /* newLineInsertedByFormatting */ newLineAdded);
parent.update(parent.parent(), parent.node(), parent.fullStart(), indentation.indentationAmount, indentation.indentationAmountDelta);
this._parent = parent;
}
}
}
}
@@ -0,0 +1,206 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class MultipleTokenIndenter extends IndentationTrackingWalker {
private _edits: TextEditInfo[] = [];
constructor(textSpan: TextSpan, sourceUnit: SourceUnitSyntax, snapshot: ITextSnapshot, indentFirstToken: boolean, options: FormattingOptions) {
super(textSpan, sourceUnit, snapshot, indentFirstToken, options);
}
public indentToken(token: ISyntaxToken, indentationAmount: number, commentIndentationAmount: number): void {
// Ignore generated tokens
if (token.fullWidth() === 0) {
return;
}
// If we have any skipped tokens as children, do not process this node for indentation or formatting
if (this.parent().hasSkippedOrMissingTokenChild()) {
return;
}
// Be strict, and only consider nodes that fall inside the span. This avoids indenting a multiline string
// on enter at the end of, as the whole token was not included in the span
var tokenSpan = new TextSpan(this.position() + token.leadingTriviaWidth(), width(token));
if (!this.textSpan().containsTextSpan(tokenSpan)) {
return;
}
// Compute an indentation string for this token
var indentationString = Indentation.indentationString(indentationAmount, this.options);
var commentIndentationString = Indentation.indentationString(commentIndentationAmount, this.options);
// Record any needed indentation edits
this.recordIndentationEditsForToken(token, indentationString, commentIndentationString);
}
public edits(): TextEditInfo[]{
return this._edits;
}
public recordEdit(position: number, length: number, replaceWith: string): void {
this._edits.push(new TextEditInfo(position, length, replaceWith));
}
private recordIndentationEditsForToken(token: ISyntaxToken, indentationString: string, commentIndentationString: string) {
var position = this.position();
var indentNextTokenOrTrivia = true;
var leadingWhiteSpace = ""; // We need to track the whitespace before a multiline comment
// Process any leading trivia if any
var triviaList = token.leadingTrivia();
if (triviaList) {
for (var i = 0, length = triviaList.count(); i < length; i++, position += trivia.fullWidth()) {
var trivia = triviaList.syntaxTriviaAt(i);
// Skip this trivia if it is not in the span
if (!this.textSpan().containsTextSpan(new TextSpan(position, trivia.fullWidth()))) {
continue;
}
switch (trivia.kind()) {
case SyntaxKind.MultiLineCommentTrivia:
// We will only indent the first line of the multiline comment if we were planning to indent the next trivia. However,
// subsequent lines will always be indented
this.recordIndentationEditsForMultiLineComment(trivia, position, commentIndentationString, leadingWhiteSpace, !indentNextTokenOrTrivia /* already indented first line */);
indentNextTokenOrTrivia = false;
leadingWhiteSpace = "";
break;
case SyntaxKind.SingleLineCommentTrivia:
case SyntaxKind.SkippedTokenTrivia:
if (indentNextTokenOrTrivia) {
this.recordIndentationEditsForSingleLineOrSkippedText(trivia, position, commentIndentationString);
indentNextTokenOrTrivia = false;
}
break;
case SyntaxKind.WhitespaceTrivia:
// If the next trivia is a comment, use the comment indentation level instead of the regular indentation level
// If the next trivia is a newline, this whole line is just whitespace, so don't do anything (trimming will take care of it)
var nextTrivia = length > i + 1 && triviaList.syntaxTriviaAt(i + 1);
var whiteSpaceIndentationString = nextTrivia && nextTrivia.isComment() ? commentIndentationString : indentationString;
if (indentNextTokenOrTrivia) {
if (!(nextTrivia && nextTrivia.isNewLine())) {
this.recordIndentationEditsForWhitespace(trivia, position, whiteSpaceIndentationString);
}
indentNextTokenOrTrivia = false;
}
leadingWhiteSpace += trivia.fullText();
break;
case SyntaxKind.NewLineTrivia:
// We hit a newline processing the trivia. We need to add the indentation to the
// next line as well. Note: don't bother indenting the newline itself. This will
// just insert ugly whitespace that most users probably will not want.
indentNextTokenOrTrivia = true;
leadingWhiteSpace = "";
break;
default:
throw Errors.invalidOperation();
}
}
}
if (token.kind() !== SyntaxKind.EndOfFileToken && indentNextTokenOrTrivia) {
// If the last trivia item was a new line, or no trivia items were encounterd record the
// indentation edit at the token position
if (indentationString.length > 0) {
this.recordEdit(position, 0, indentationString);
}
}
}
private recordIndentationEditsForSingleLineOrSkippedText(trivia: ISyntaxTrivia, fullStart: number, indentationString: string): void {
// Record the edit
if (indentationString.length > 0) {
this.recordEdit(fullStart, 0, indentationString);
}
}
private recordIndentationEditsForWhitespace(trivia: ISyntaxTrivia, fullStart: number, indentationString: string): void {
var text = trivia.fullText();
// Check if the current indentation matches the desired indentation or not
if (indentationString === text) {
return;
}
// Record the edit
this.recordEdit(fullStart, text.length, indentationString);
}
private recordIndentationEditsForMultiLineComment(trivia: ISyntaxTrivia, fullStart: number, indentationString: string, leadingWhiteSpace: string, firstLineAlreadyIndented: boolean): void {
// If the multiline comment spans multiple lines, we need to add the right indent amount to
// each successive line segment as well.
var position = fullStart;
var segments = Syntax.splitMultiLineCommentTriviaIntoMultipleLines(trivia);
if (segments.length <= 1) {
if (!firstLineAlreadyIndented) {
// Process the one-line multiline comment just like a single line comment
this.recordIndentationEditsForSingleLineOrSkippedText(trivia, fullStart, indentationString);
}
return;
}
// Find number of columns in first segment
var whiteSpaceColumnsInFirstSegment = Indentation.columnForPositionInString(leadingWhiteSpace, leadingWhiteSpace.length, this.options);
var indentationColumns = Indentation.columnForPositionInString(indentationString, indentationString.length, this.options);
var startIndex = 0;
if (firstLineAlreadyIndented) {
startIndex = 1;
position += segments[0].length;
}
for (var i = startIndex; i < segments.length; i++) {
var segment = segments[i];
this.recordIndentationEditsForSegment(segment, position, indentationColumns, whiteSpaceColumnsInFirstSegment);
position += segment.length;
}
}
private recordIndentationEditsForSegment(segment: string, fullStart: number, indentationColumns: number, whiteSpaceColumnsInFirstSegment: number): void {
// Indent subsequent lines using a column delta of the actual indentation relative to the first line
var firstNonWhitespacePosition = Indentation.firstNonWhitespacePosition(segment);
var leadingWhiteSpaceColumns = Indentation.columnForPositionInString(segment, firstNonWhitespacePosition, this.options);
var deltaFromFirstSegment = leadingWhiteSpaceColumns - whiteSpaceColumnsInFirstSegment;
var finalColumns = indentationColumns + deltaFromFirstSegment;
if (finalColumns < 0) {
finalColumns = 0;
}
var indentationString = Indentation.indentationString(finalColumns, this.options);
if (firstNonWhitespacePosition < segment.length &&
CharacterInfo.isLineTerminator(segment.charCodeAt(firstNonWhitespacePosition))) {
// If this segment was just a newline, then don't bother indenting it. That will just
// leave the user with an ugly indent in their output that they probably do not want.
return;
}
if (indentationString === segment.substring(0, firstNonWhitespacePosition)) {
return;
}
// Record the edit
this.recordEdit(fullStart, firstNonWhitespacePosition, indentationString);
}
}
}
+32
View File
@@ -0,0 +1,32 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class Rule {
constructor(
public Descriptor: RuleDescriptor,
public Operation: RuleOperation,
public Flag: RuleFlags = RuleFlags.None) {
}
public toString() {
return "[desc=" + this.Descriptor + "," +
"operation=" + this.Operation + "," +
"flag=" + this.Flag + "]";
}
}
}
+25
View File
@@ -0,0 +1,25 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export enum RuleAction {
Ignore,
Space,
NewLine,
Delete
}
}
+46
View File
@@ -0,0 +1,46 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class RuleDescriptor {
constructor(public LeftTokenRange: Shared.TokenRange, public RightTokenRange: Shared.TokenRange) {
}
public toString(): string {
return "[leftRange=" + this.LeftTokenRange + "," +
"rightRange=" + this.RightTokenRange + "]";
}
static create1(left: SyntaxKind, right: SyntaxKind): RuleDescriptor {
return RuleDescriptor.create4(Shared.TokenRange.FromToken(left), Shared.TokenRange.FromToken(right))
}
static create2(left: Shared.TokenRange, right: SyntaxKind): RuleDescriptor {
return RuleDescriptor.create4(left, Shared.TokenRange.FromToken(right));
}
static create3(left: SyntaxKind, right: Shared.TokenRange): RuleDescriptor
//: this(TokenRange.FromToken(left), right)
{
return RuleDescriptor.create4(Shared.TokenRange.FromToken(left), right);
}
static create4(left: Shared.TokenRange, right: Shared.TokenRange): RuleDescriptor {
return new RuleDescriptor(left, right);
}
}
}
+23
View File
@@ -0,0 +1,23 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export enum RuleFlags {
None,
CanDeleteNewLines
}
}
+44
View File
@@ -0,0 +1,44 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class RuleOperation {
public Context: RuleOperationContext;
public Action: RuleAction;
constructor() {
this.Context = null;
this.Action = null;
}
public toString(): string {
return "[context=" + this.Context + "," +
"action=" + this.Action + "]";
}
static create1(action: RuleAction) {
return RuleOperation.create2(RuleOperationContext.Any, action)
}
static create2(context: RuleOperationContext, action: RuleAction) {
var result = new RuleOperation();
result.Context = context;
result.Action = action;
return result;
}
}
}
@@ -0,0 +1,47 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class RuleOperationContext {
private customContextChecks: { (context: FormattingContext): boolean; }[];
constructor(...funcs: { (context: FormattingContext): boolean; }[]) {
this.customContextChecks = funcs;
}
static Any: RuleOperationContext = new RuleOperationContext();
public IsAny(): boolean {
return this == RuleOperationContext.Any;
}
public InContext(context: FormattingContext): boolean {
if (this.IsAny()) {
return true;
}
for (var i = 0, len = this.customContextChecks.length; i < len; i++) {
if (!this.customContextChecks[i](context)) {
return false;
}
}
return true;
}
}
}
+678
View File
@@ -0,0 +1,678 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class Rules {
public getRuleName(rule: Rule) {
var o: ts.Map<any> = <any>this;
for (var name in o) {
if (o[name] === rule) {
return name;
}
}
throw new Error(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.Unknown_rule, null));
}
[name: string]: any;
public IgnoreBeforeComment: Rule;
public IgnoreAfterLineComment: Rule;
// Space after keyword but not before ; or : or ?
public NoSpaceBeforeSemicolon: Rule;
public NoSpaceBeforeColon: Rule;
public NoSpaceBeforeQMark: Rule;
public SpaceAfterColon: Rule;
public SpaceAfterQMark: Rule;
public SpaceAfterSemicolon: Rule;
// Space/new line after }.
public SpaceAfterCloseBrace: Rule;
// Special case for (}, else) and (}, while) since else & while tokens are not part of the tree which makes SpaceAfterCloseBrace rule not applied
// Also should not apply to })
public SpaceBetweenCloseBraceAndElse: Rule;
public SpaceBetweenCloseBraceAndWhile: Rule;
public NoSpaceAfterCloseBrace: Rule;
// No space for indexer and dot
public NoSpaceBeforeDot: Rule;
public NoSpaceAfterDot: Rule;
public NoSpaceBeforeOpenBracket: Rule;
public NoSpaceAfterOpenBracket: Rule;
public NoSpaceBeforeCloseBracket: Rule;
public NoSpaceAfterCloseBracket: Rule;
// Insert a space after { and before } in single-line contexts, but remove space from empty object literals {}.
public SpaceAfterOpenBrace: Rule;
public SpaceBeforeCloseBrace: Rule;
public NoSpaceBetweenEmptyBraceBrackets: Rule;
// Insert new line after { and before } in multi-line contexts.
public NewLineAfterOpenBraceInBlockContext: Rule;
// For functions and control block place } on a new line [multi-line rule]
public NewLineBeforeCloseBraceInBlockContext: Rule;
// Special handling of unary operators.
// Prefix operators generally shouldn't have a space between
// them and their target unary expression.
public NoSpaceAfterUnaryPrefixOperator: Rule;
public NoSpaceAfterUnaryPreincrementOperator: Rule;
public NoSpaceAfterUnaryPredecrementOperator: Rule;
public NoSpaceBeforeUnaryPostincrementOperator: Rule;
public NoSpaceBeforeUnaryPostdecrementOperator: Rule;
// More unary operator special-casing.
// DevDiv 181814: Be careful when removing leading whitespace
// around unary operators. Examples:
// 1 - -2 --X--> 1--2
// a + ++b --X--> a+++b
public SpaceAfterPostincrementWhenFollowedByAdd: Rule;
public SpaceAfterAddWhenFollowedByUnaryPlus: Rule;
public SpaceAfterAddWhenFollowedByPreincrement: Rule;
public SpaceAfterPostdecrementWhenFollowedBySubtract: Rule;
public SpaceAfterSubtractWhenFollowedByUnaryMinus: Rule;
public SpaceAfterSubtractWhenFollowedByPredecrement: Rule;
public NoSpaceBeforeComma: Rule;
public SpaceAfterCertainKeywords: Rule;
public NoSpaceBeforeOpenParenInFuncCall: Rule;
public SpaceAfterFunctionInFuncDecl: Rule;
public NoSpaceBeforeOpenParenInFuncDecl: Rule;
public SpaceAfterVoidOperator: Rule;
public NoSpaceBetweenReturnAndSemicolon: Rule;
// Add a space between statements. All keywords except (do,else,case) has open/close parens after them.
// So, we have a rule to add a space for [),Any], [do,Any], [else,Any], and [case,Any]
public SpaceBetweenStatements: Rule;
// This low-pri rule takes care of "try {" and "finally {" in case the rule SpaceBeforeOpenBraceInControl didn't execute on FormatOnEnter.
public SpaceAfterTryFinally: Rule;
// For get/set members, we check for (identifier,identifier) since get/set don't have tokens and they are represented as just an identifier token.
// Though, we do extra check on the context to make sure we are dealing with get/set node. Example:
// get x() {}
// set x(val) {}
public SpaceAfterGetSetInMember: Rule;
// Special case for binary operators (that are keywords). For these we have to add a space and shouldn't follow any user options.
public SpaceBeforeBinaryKeywordOperator: Rule;
public SpaceAfterBinaryKeywordOperator: Rule;
// TypeScript-specific rules
// Treat constructor as an identifier in a function declaration, and remove spaces between constructor and following left parentheses
public NoSpaceAfterConstructor: Rule;
// Use of module as a function call. e.g.: import m2 = module("m2");
public NoSpaceAfterModuleImport: Rule;
// Add a space around certain TypeScript keywords
public SpaceAfterCertainTypeScriptKeywords: Rule;
public SpaceBeforeCertainTypeScriptKeywords: Rule;
// Treat string literals in module names as identifiers, and add a space between the literal and the opening Brace braces, e.g.: module "m2" {
public SpaceAfterModuleName: Rule;
// Lambda expressions
public SpaceAfterArrow: Rule;
// Optional parameters and var args
public NoSpaceAfterEllipsis: Rule;
public NoSpaceAfterOptionalParameters: Rule;
// generics
public NoSpaceBeforeOpenAngularBracket: Rule;
public NoSpaceBetweenCloseParenAndAngularBracket: Rule;
public NoSpaceAfterOpenAngularBracket: Rule;
public NoSpaceBeforeCloseAngularBracket: Rule;
public NoSpaceAfterCloseAngularBracket: Rule;
// Remove spaces in empty interface literals. e.g.: x: {}
public NoSpaceBetweenEmptyInterfaceBraceBrackets: Rule;
// These rules are higher in priority than user-configurable rules.
public HighPriorityCommonRules: Rule[];
// These rules are lower in priority than user-configurable rules.
public LowPriorityCommonRules: Rule[];
///
/// Rules controlled by user options
///
// Insert space after comma delimiter
public SpaceAfterComma: Rule;
public NoSpaceAfterComma: Rule;
// Insert space before and after binary operators
public SpaceBeforeBinaryOperator: Rule;
public SpaceAfterBinaryOperator: Rule;
public NoSpaceBeforeBinaryOperator: Rule;
public NoSpaceAfterBinaryOperator: Rule;
// Insert space after keywords in control flow statements
public SpaceAfterKeywordInControl: Rule;
public NoSpaceAfterKeywordInControl: Rule;
// Open Brace braces after function
//TypeScript: Function can have return types, which can be made of tons of different token kinds
public FunctionOpenBraceLeftTokenRange: Shared.TokenRange;
public SpaceBeforeOpenBraceInFunction: Rule;
public NewLineBeforeOpenBraceInFunction: Rule;
// Open Brace braces after TypeScript module/class/interface
public TypeScriptOpenBraceLeftTokenRange: Shared.TokenRange;
public SpaceBeforeOpenBraceInTypeScriptDeclWithBlock: Rule;
public NewLineBeforeOpenBraceInTypeScriptDeclWithBlock: Rule;
// Open Brace braces after control block
public ControlOpenBraceLeftTokenRange: Shared.TokenRange;
public SpaceBeforeOpenBraceInControl: Rule;
public NewLineBeforeOpenBraceInControl: Rule;
// Insert space after semicolon in for statement
public SpaceAfterSemicolonInFor: Rule;
public NoSpaceAfterSemicolonInFor: Rule;
// Insert space after opening and before closing nonempty parenthesis
public SpaceAfterOpenParen: Rule;
public SpaceBeforeCloseParen: Rule;
public NoSpaceBetweenParens: Rule;
public NoSpaceAfterOpenParen: Rule;
public NoSpaceBeforeCloseParen: Rule;
// Insert space after function keyword for anonymous functions
public SpaceAfterAnonymousFunctionKeyword: Rule;
public NoSpaceAfterAnonymousFunctionKeyword: Rule;
constructor() {
///
/// Common Rules
///
// Leave comments alone
this.IgnoreBeforeComment = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.Comments), RuleOperation.create1(RuleAction.Ignore));
this.IgnoreAfterLineComment = new Rule(RuleDescriptor.create3(SyntaxKind.SingleLineCommentTrivia, Shared.TokenRange.Any), RuleOperation.create1(RuleAction.Ignore));
// Space after keyword but not before ; or : or ?
this.NoSpaceBeforeSemicolon = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.SemicolonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
this.NoSpaceBeforeColon = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.ColonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete));
this.NoSpaceBeforeQMark = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.QuestionToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete));
this.SpaceAfterColon = new Rule(RuleDescriptor.create3(SyntaxKind.ColonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Space));
this.SpaceAfterQMark = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Space));
this.SpaceAfterSemicolon = new Rule(RuleDescriptor.create3(SyntaxKind.SemicolonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
// Space after }.
this.SpaceAfterCloseBrace = new Rule(RuleDescriptor.create3(SyntaxKind.CloseBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsAfterCodeBlockContext), RuleAction.Space));
// Special case for (}, else) and (}, while) since else & while tokens are not part of the tree which makes SpaceAfterCloseBrace rule not applied
this.SpaceBetweenCloseBraceAndElse = new Rule(RuleDescriptor.create1(SyntaxKind.CloseBraceToken, SyntaxKind.ElseKeyword), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
this.SpaceBetweenCloseBraceAndWhile = new Rule(RuleDescriptor.create1(SyntaxKind.CloseBraceToken, SyntaxKind.WhileKeyword), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
this.NoSpaceAfterCloseBrace = new Rule(RuleDescriptor.create3(SyntaxKind.CloseBraceToken, Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.CommaToken, SyntaxKind.SemicolonToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
// No space for indexer and dot
this.NoSpaceBeforeDot = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.DotToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
this.NoSpaceAfterDot = new Rule(RuleDescriptor.create3(SyntaxKind.DotToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
this.NoSpaceBeforeOpenBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenBracketToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
this.NoSpaceAfterOpenBracket = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBracketToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
this.NoSpaceBeforeCloseBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBracketToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
this.NoSpaceAfterCloseBracket = new Rule(RuleDescriptor.create3(SyntaxKind.CloseBracketToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
// Place a space before open brace in a function declaration
this.FunctionOpenBraceLeftTokenRange = Shared.TokenRange.AnyIncludingMultilineComments;
this.SpaceBeforeOpenBraceInFunction = new Rule(RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);
// Place a space before open brace in a TypeScript declaration that has braces as children (class, module, enum, etc)
this.TypeScriptOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.MultiLineCommentTrivia]);
this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock = new Rule(RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsTypeScriptDeclWithBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);
// Place a space before open brace in a control flow construct
this.ControlOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.MultiLineCommentTrivia, SyntaxKind.DoKeyword, SyntaxKind.TryKeyword, SyntaxKind.FinallyKeyword, SyntaxKind.ElseKeyword]);
this.SpaceBeforeOpenBraceInControl = new Rule(RuleDescriptor.create2(this.ControlOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsControlDeclContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);
// Insert a space after { and before } in single-line contexts, but remove space from empty object literals {}.
this.SpaceAfterOpenBrace = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSingleLineBlockContext), RuleAction.Space));
this.SpaceBeforeCloseBrace = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSingleLineBlockContext), RuleAction.Space));
this.NoSpaceBetweenEmptyBraceBrackets = new Rule(RuleDescriptor.create1(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsObjectContext), RuleAction.Delete));
// Insert new line after { and before } in multi-line contexts.
this.NewLineAfterOpenBraceInBlockContext = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsMultilineBlockContext), RuleAction.NewLine));
// For functions and control block place } on a new line [multi-line rule]
this.NewLineBeforeCloseBraceInBlockContext = new Rule(RuleDescriptor.create2(Shared.TokenRange.AnyIncludingMultilineComments, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsMultilineBlockContext), RuleAction.NewLine));
// Special handling of unary operators.
// Prefix operators generally shouldn't have a space between
// them and their target unary expression.
this.NoSpaceAfterUnaryPrefixOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.UnaryPrefixOperators, Shared.TokenRange.UnaryPrefixExpressions), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete));
this.NoSpaceAfterUnaryPreincrementOperator = new Rule(RuleDescriptor.create3(SyntaxKind.PlusPlusToken, Shared.TokenRange.UnaryPreincrementExpressions), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
this.NoSpaceAfterUnaryPredecrementOperator = new Rule(RuleDescriptor.create3(SyntaxKind.MinusMinusToken, Shared.TokenRange.UnaryPredecrementExpressions), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
this.NoSpaceBeforeUnaryPostincrementOperator = new Rule(RuleDescriptor.create2(Shared.TokenRange.UnaryPostincrementExpressions, SyntaxKind.PlusPlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
this.NoSpaceBeforeUnaryPostdecrementOperator = new Rule(RuleDescriptor.create2(Shared.TokenRange.UnaryPostdecrementExpressions, SyntaxKind.MinusMinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
// More unary operator special-casing.
// DevDiv 181814: Be careful when removing leading whitespace
// around unary operators. Examples:
// 1 - -2 --X--> 1--2
// a + ++b --X--> a+++b
this.SpaceAfterPostincrementWhenFollowedByAdd = new Rule(RuleDescriptor.create1(SyntaxKind.PlusPlusToken, SyntaxKind.PlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
this.SpaceAfterAddWhenFollowedByUnaryPlus = new Rule(RuleDescriptor.create1(SyntaxKind.PlusToken, SyntaxKind.PlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
this.SpaceAfterAddWhenFollowedByPreincrement = new Rule(RuleDescriptor.create1(SyntaxKind.PlusToken, SyntaxKind.PlusPlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
this.SpaceAfterPostdecrementWhenFollowedBySubtract = new Rule(RuleDescriptor.create1(SyntaxKind.MinusMinusToken, SyntaxKind.MinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
this.SpaceAfterSubtractWhenFollowedByUnaryMinus = new Rule(RuleDescriptor.create1(SyntaxKind.MinusToken, SyntaxKind.MinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
this.SpaceAfterSubtractWhenFollowedByPredecrement = new Rule(RuleDescriptor.create1(SyntaxKind.MinusToken, SyntaxKind.MinusMinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
this.NoSpaceBeforeComma = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CommaToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
this.SpaceAfterCertainKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.VarKeyword, SyntaxKind.ThrowKeyword, SyntaxKind.NewKeyword, SyntaxKind.DeleteKeyword, SyntaxKind.ReturnKeyword, SyntaxKind.TypeOfKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
this.NoSpaceBeforeOpenParenInFuncCall = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsFunctionCallOrNewContext), RuleAction.Delete));
this.SpaceAfterFunctionInFuncDecl = new Rule(RuleDescriptor.create3(SyntaxKind.FunctionKeyword, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space));
this.NoSpaceBeforeOpenParenInFuncDecl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsFunctionDeclContext), RuleAction.Delete));
this.SpaceAfterVoidOperator = new Rule(RuleDescriptor.create3(SyntaxKind.VoidKeyword, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsVoidOpContext), RuleAction.Space));
this.NoSpaceBetweenReturnAndSemicolon = new Rule(RuleDescriptor.create1(SyntaxKind.ReturnKeyword, SyntaxKind.SemicolonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
// Add a space between statements. All keywords except (do,else,case) has open/close parens after them.
// So, we have a rule to add a space for [),Any], [do,Any], [else,Any], and [case,Any]
this.SpaceBetweenStatements = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.DoKeyword, SyntaxKind.ElseKeyword, SyntaxKind.CaseKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotForContext), RuleAction.Space));
// This low-pri rule takes care of "try {" and "finally {" in case the rule SpaceBeforeOpenBraceInControl didn't execute on FormatOnEnter.
this.SpaceAfterTryFinally = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.TryKeyword, SyntaxKind.FinallyKeyword]), SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
// get x() {}
// set x(val) {}
this.SpaceAfterGetSetInMember = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.GetKeyword, SyntaxKind.SetKeyword]), SyntaxKind.IdentifierName), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space));
// Special case for binary operators (that are keywords). For these we have to add a space and shouldn't follow any user options.
this.SpaceBeforeBinaryKeywordOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryKeywordOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
this.SpaceAfterBinaryKeywordOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.BinaryKeywordOperators, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
// TypeScript-specific higher priority rules
// Treat constructor as an identifier in a function declaration, and remove spaces between constructor and following left parentheses
this.NoSpaceAfterConstructor = new Rule(RuleDescriptor.create1(SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
// Use of module as a function call. e.g.: import m2 = module("m2");
this.NoSpaceAfterModuleImport = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.ModuleKeyword, SyntaxKind.RequireKeyword]), SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
// Add a space around certain TypeScript keywords
this.SpaceAfterCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.ClassKeyword, SyntaxKind.DeclareKeyword, SyntaxKind.EnumKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ExtendsKeyword, SyntaxKind.GetKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.ImportKeyword, SyntaxKind.InterfaceKeyword, SyntaxKind.ModuleKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.PublicKeyword, SyntaxKind.SetKeyword, SyntaxKind.StaticKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
this.SpaceBeforeCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.ExtendsKeyword, SyntaxKind.ImplementsKeyword])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
// Treat string literals in module names as identifiers, and add a space between the literal and the opening Brace braces, e.g.: module "m2" {
this.SpaceAfterModuleName = new Rule(RuleDescriptor.create1(SyntaxKind.StringLiteral, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsModuleDeclContext), RuleAction.Space));
// Lambda expressions
this.SpaceAfterArrow = new Rule(RuleDescriptor.create3(SyntaxKind.EqualsGreaterThanToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
// Optional parameters and var args
this.NoSpaceAfterEllipsis = new Rule(RuleDescriptor.create1(SyntaxKind.DotDotDotToken, SyntaxKind.IdentifierName), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
this.NoSpaceAfterOptionalParameters = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.CommaToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete));
// generics
this.NoSpaceBeforeOpenAngularBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.TypeNames, SyntaxKind.LessThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), RuleAction.Delete));
this.NoSpaceBetweenCloseParenAndAngularBracket = new Rule(RuleDescriptor.create1(SyntaxKind.CloseParenToken, SyntaxKind.LessThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), RuleAction.Delete));
this.NoSpaceAfterOpenAngularBracket = new Rule(RuleDescriptor.create3(SyntaxKind.LessThanToken, Shared.TokenRange.TypeNames), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), RuleAction.Delete));
this.NoSpaceBeforeCloseAngularBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.GreaterThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), RuleAction.Delete));
this.NoSpaceAfterCloseAngularBracket = new Rule(RuleDescriptor.create3(SyntaxKind.GreaterThanToken, Shared.TokenRange.FromTokens([SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.GreaterThanToken, SyntaxKind.CommaToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsTypeArgumentOrParameterContext), RuleAction.Delete));
// Remove spaces in empty interface literals. e.g.: x: {}
this.NoSpaceBetweenEmptyInterfaceBraceBrackets = new Rule(RuleDescriptor.create1(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsObjectTypeContext), RuleAction.Delete));
// These rules are higher in priority than user-configurable rules.
this.HighPriorityCommonRules =
[
this.IgnoreBeforeComment, this.IgnoreAfterLineComment,
this.NoSpaceBeforeColon, this.SpaceAfterColon, this.NoSpaceBeforeQMark, this.SpaceAfterQMark,
this.NoSpaceBeforeDot, this.NoSpaceAfterDot,
this.NoSpaceAfterUnaryPrefixOperator,
this.NoSpaceAfterUnaryPreincrementOperator, this.NoSpaceAfterUnaryPredecrementOperator,
this.NoSpaceBeforeUnaryPostincrementOperator, this.NoSpaceBeforeUnaryPostdecrementOperator,
this.SpaceAfterPostincrementWhenFollowedByAdd,
this.SpaceAfterAddWhenFollowedByUnaryPlus, this.SpaceAfterAddWhenFollowedByPreincrement,
this.SpaceAfterPostdecrementWhenFollowedBySubtract,
this.SpaceAfterSubtractWhenFollowedByUnaryMinus, this.SpaceAfterSubtractWhenFollowedByPredecrement,
this.NoSpaceAfterCloseBrace,
this.SpaceAfterOpenBrace, this.SpaceBeforeCloseBrace, this.NewLineBeforeCloseBraceInBlockContext,
this.SpaceAfterCloseBrace, this.SpaceBetweenCloseBraceAndElse, this.SpaceBetweenCloseBraceAndWhile, this.NoSpaceBetweenEmptyBraceBrackets,
this.SpaceAfterFunctionInFuncDecl, this.NewLineAfterOpenBraceInBlockContext, this.SpaceAfterGetSetInMember,
this.NoSpaceBetweenReturnAndSemicolon,
this.SpaceAfterCertainKeywords,
this.NoSpaceBeforeOpenParenInFuncCall,
this.SpaceBeforeBinaryKeywordOperator, this.SpaceAfterBinaryKeywordOperator,
this.SpaceAfterVoidOperator,
// TypeScript-specific rules
this.NoSpaceAfterConstructor, this.NoSpaceAfterModuleImport,
this.SpaceAfterCertainTypeScriptKeywords, this.SpaceBeforeCertainTypeScriptKeywords,
this.SpaceAfterModuleName,
this.SpaceAfterArrow,
this.NoSpaceAfterEllipsis,
this.NoSpaceAfterOptionalParameters,
this.NoSpaceBetweenEmptyInterfaceBraceBrackets,
this.NoSpaceBeforeOpenAngularBracket,
this.NoSpaceBetweenCloseParenAndAngularBracket,
this.NoSpaceAfterOpenAngularBracket,
this.NoSpaceBeforeCloseAngularBracket,
this.NoSpaceAfterCloseAngularBracket
];
// These rules are lower in priority than user-configurable rules.
this.LowPriorityCommonRules =
[
this.NoSpaceBeforeSemicolon,
this.SpaceBeforeOpenBraceInControl, this.SpaceBeforeOpenBraceInFunction, this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock,
this.NoSpaceBeforeComma,
this.NoSpaceBeforeOpenBracket, this.NoSpaceAfterOpenBracket,
this.NoSpaceBeforeCloseBracket, this.NoSpaceAfterCloseBracket,
this.SpaceAfterSemicolon,
this.NoSpaceBeforeOpenParenInFuncDecl,
this.SpaceBetweenStatements, this.SpaceAfterTryFinally
];
///
/// Rules controlled by user options
///
// Insert space after comma delimiter
this.SpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
this.NoSpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
// Insert space before and after binary operators
this.SpaceBeforeBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
this.SpaceAfterBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.BinaryOperators, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
this.NoSpaceBeforeBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Delete));
this.NoSpaceAfterBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.BinaryOperators, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Delete));
// Insert space after keywords in control flow statements
this.SpaceAfterKeywordInControl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Keywords, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsControlDeclContext), RuleAction.Space));
this.NoSpaceAfterKeywordInControl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Keywords, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsControlDeclContext), RuleAction.Delete));
// Open Brace braces after function
//TypeScript: Function can have return types, which can be made of tons of different token kinds
this.NewLineBeforeOpenBraceInFunction = new Rule(RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext, Rules.IsBeforeMultilineBlockContext), RuleAction.NewLine), RuleFlags.CanDeleteNewLines);
// Open Brace braces after TypeScript module/class/interface
this.NewLineBeforeOpenBraceInTypeScriptDeclWithBlock = new Rule(RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsTypeScriptDeclWithBlockContext, Rules.IsBeforeMultilineBlockContext), RuleAction.NewLine), RuleFlags.CanDeleteNewLines);
// Open Brace braces after control block
this.NewLineBeforeOpenBraceInControl = new Rule(RuleDescriptor.create2(this.ControlOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsControlDeclContext, Rules.IsBeforeMultilineBlockContext), RuleAction.NewLine), RuleFlags.CanDeleteNewLines);
// Insert space after semicolon in for statement
this.SpaceAfterSemicolonInFor = new Rule(RuleDescriptor.create3(SyntaxKind.SemicolonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsForContext), RuleAction.Space));
this.NoSpaceAfterSemicolonInFor = new Rule(RuleDescriptor.create3(SyntaxKind.SemicolonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsForContext), RuleAction.Delete));
// Insert space after opening and before closing nonempty parenthesis
this.SpaceAfterOpenParen = new Rule(RuleDescriptor.create3(SyntaxKind.OpenParenToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
this.SpaceBeforeCloseParen = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
this.NoSpaceBetweenParens = new Rule(RuleDescriptor.create1(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
this.NoSpaceAfterOpenParen = new Rule(RuleDescriptor.create3(SyntaxKind.OpenParenToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
this.NoSpaceBeforeCloseParen = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
// Insert space after function keyword for anonymous functions
this.SpaceAfterAnonymousFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space));
this.NoSpaceAfterAnonymousFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Delete));
}
///
/// Contexts
///
static IsForContext(context: FormattingContext): boolean {
return context.contextNode.kind() === SyntaxKind.ForStatement;
}
static IsNotForContext(context: FormattingContext): boolean {
return !Rules.IsForContext(context);
}
static IsBinaryOpContext(context: FormattingContext): boolean {
switch (context.contextNode.kind()) {
// binary expressions
case SyntaxKind.AssignmentExpression:
case SyntaxKind.AddAssignmentExpression:
case SyntaxKind.SubtractAssignmentExpression:
case SyntaxKind.MultiplyAssignmentExpression:
case SyntaxKind.DivideAssignmentExpression:
case SyntaxKind.ModuloAssignmentExpression:
case SyntaxKind.AndAssignmentExpression:
case SyntaxKind.ExclusiveOrAssignmentExpression:
case SyntaxKind.OrAssignmentExpression:
case SyntaxKind.LeftShiftAssignmentExpression:
case SyntaxKind.SignedRightShiftAssignmentExpression:
case SyntaxKind.UnsignedRightShiftAssignmentExpression:
case SyntaxKind.ConditionalExpression:
case SyntaxKind.LogicalOrExpression:
case SyntaxKind.LogicalAndExpression:
case SyntaxKind.BitwiseOrExpression:
case SyntaxKind.BitwiseExclusiveOrExpression:
case SyntaxKind.BitwiseAndExpression:
case SyntaxKind.EqualsWithTypeConversionExpression:
case SyntaxKind.NotEqualsWithTypeConversionExpression:
case SyntaxKind.EqualsExpression:
case SyntaxKind.NotEqualsExpression:
case SyntaxKind.LessThanExpression:
case SyntaxKind.GreaterThanExpression:
case SyntaxKind.LessThanOrEqualExpression:
case SyntaxKind.GreaterThanOrEqualExpression:
case SyntaxKind.InstanceOfExpression:
case SyntaxKind.InExpression:
case SyntaxKind.LeftShiftExpression:
case SyntaxKind.SignedRightShiftExpression:
case SyntaxKind.UnsignedRightShiftExpression:
case SyntaxKind.MultiplyExpression:
case SyntaxKind.DivideExpression:
case SyntaxKind.ModuloExpression:
case SyntaxKind.AddExpression:
case SyntaxKind.SubtractExpression:
return true;
// equal in import a = module('a');
case SyntaxKind.ImportDeclaration:
// equal in var a = 0;
case SyntaxKind.VariableDeclarator:
case SyntaxKind.EqualsValueClause:
return context.currentTokenSpan.kind === SyntaxKind.EqualsToken || context.nextTokenSpan.kind === SyntaxKind.EqualsToken;
// "in" keyword in for (var x in []) { }
case SyntaxKind.ForInStatement:
return context.currentTokenSpan.kind === SyntaxKind.InKeyword || context.nextTokenSpan.kind === SyntaxKind.InKeyword;
}
return false;
}
static IsNotBinaryOpContext(context: FormattingContext): boolean {
return !Rules.IsBinaryOpContext(context);
}
static IsSameLineTokenOrBeforeMultilineBlockContext(context: FormattingContext): boolean {
//// This check is mainly used inside SpaceBeforeOpenBraceInControl and SpaceBeforeOpenBraceInFunction.
////
//// Ex:
//// if (1) { ....
//// * ) and { are on the same line so apply the rule. Here we don't care whether it's same or multi block context
////
//// Ex:
//// if (1)
//// { ... }
//// * ) and { are on differnet lines. We only need to format if the block is multiline context. So in this case we don't format.
////
//// Ex:
//// if (1)
//// { ...
//// }
//// * ) and { are on differnet lines. We only need to format if the block is multiline context. So in this case we format.
return context.TokensAreOnSameLine() || Rules.IsBeforeMultilineBlockContext(context);
}
// This check is done before an open brace in a control construct, a function, or a typescript block declaration
static IsBeforeMultilineBlockContext(context: FormattingContext): boolean {
return Rules.IsBeforeBlockContext(context) && !(context.NextNodeAllOnSameLine() || context.NextNodeBlockIsOnOneLine());
}
static IsMultilineBlockContext(context: FormattingContext): boolean {
return Rules.IsBlockContext(context) && !(context.ContextNodeAllOnSameLine() || context.ContextNodeBlockIsOnOneLine());
}
static IsSingleLineBlockContext(context: FormattingContext): boolean {
return Rules.IsBlockContext(context) && (context.ContextNodeAllOnSameLine() || context.ContextNodeBlockIsOnOneLine());
}
static IsBlockContext(context: FormattingContext): boolean {
return Rules.NodeIsBlockContext(context.contextNode);
}
static IsBeforeBlockContext(context: FormattingContext): boolean {
return Rules.NodeIsBlockContext(context.nextTokenParent);
}
// IMPORTANT!!! This method must return true ONLY for nodes with open and close braces as immediate children
static NodeIsBlockContext(node: IndentationNodeContext): boolean {
if (Rules.NodeIsTypeScriptDeclWithBlockContext(node)) {
// This means we are in a context that looks like a block to the user, but in the grammar is actually not a node (it's a class, module, enum, object type literal, etc).
return true;
}
switch (node.kind()) {
case SyntaxKind.Block:
case SyntaxKind.SwitchStatement:
case SyntaxKind.ObjectLiteralExpression:
return true;
}
return false;
}
static IsFunctionDeclContext(context: FormattingContext): boolean {
switch (context.contextNode.kind()) {
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.MemberFunctionDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.MethodSignature:
case SyntaxKind.CallSignature:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ConstructorDeclaration:
case SyntaxKind.SimpleArrowFunctionExpression:
case SyntaxKind.ParenthesizedArrowFunctionExpression:
case SyntaxKind.InterfaceDeclaration: // This one is not truly a function, but for formatting purposes, it acts just like one
return true;
}
return false;
}
static IsTypeScriptDeclWithBlockContext(context: FormattingContext): boolean {
return Rules.NodeIsTypeScriptDeclWithBlockContext(context.contextNode);
}
static NodeIsTypeScriptDeclWithBlockContext(node: IndentationNodeContext): boolean {
switch (node.kind()) {
case SyntaxKind.ClassDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.ObjectType:
case SyntaxKind.ModuleDeclaration:
return true;
}
return false;
}
static IsAfterCodeBlockContext(context: FormattingContext): boolean {
switch (context.currentTokenParent.kind()) {
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.Block:
case SyntaxKind.SwitchStatement:
return true;
}
return false;
}
static IsControlDeclContext(context: FormattingContext): boolean {
switch (context.contextNode.kind()) {
case SyntaxKind.IfStatement:
case SyntaxKind.SwitchStatement:
case SyntaxKind.ForStatement:
case SyntaxKind.ForInStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.TryStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.WithStatement:
case SyntaxKind.ElseClause:
case SyntaxKind.CatchClause:
case SyntaxKind.FinallyClause:
return true;
default:
return false;
}
}
static IsObjectContext(context: FormattingContext): boolean {
return context.contextNode.kind() === SyntaxKind.ObjectLiteralExpression;
}
static IsFunctionCallContext(context: FormattingContext): boolean {
return context.contextNode.kind() === SyntaxKind.InvocationExpression;
}
static IsNewContext(context: FormattingContext): boolean {
return context.contextNode.kind() === SyntaxKind.ObjectCreationExpression;
}
static IsFunctionCallOrNewContext(context: FormattingContext): boolean {
return Rules.IsFunctionCallContext(context) || Rules.IsNewContext(context);
}
static IsSameLineTokenContext(context: FormattingContext): boolean {
return context.TokensAreOnSameLine();
}
static IsNotFormatOnEnter(context: FormattingContext): boolean {
return context.formattingRequestKind != FormattingRequestKind.FormatOnEnter;
}
static IsModuleDeclContext(context: FormattingContext): boolean {
return context.contextNode.kind() === SyntaxKind.ModuleDeclaration;
}
static IsObjectTypeContext(context: FormattingContext): boolean {
return context.contextNode.kind() === SyntaxKind.ObjectType && context.contextNode.parent().kind() !== SyntaxKind.InterfaceDeclaration;
}
static IsTypeArgumentOrParameter(tokenKind: SyntaxKind, parentKind: SyntaxKind): boolean {
return ((tokenKind === SyntaxKind.LessThanToken || tokenKind === SyntaxKind.GreaterThanToken) &&
(parentKind === SyntaxKind.TypeParameterList || parentKind === SyntaxKind.TypeArgumentList));
}
static IsTypeArgumentOrParameterContext(context: FormattingContext): boolean {
return Rules.IsTypeArgumentOrParameter(context.currentTokenSpan.kind, context.currentTokenParent.kind()) ||
Rules.IsTypeArgumentOrParameter(context.nextTokenSpan.kind, context.nextTokenParent.kind());
}
static IsVoidOpContext(context: FormattingContext): boolean {
return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword && context.currentTokenParent.kind() === SyntaxKind.VoidExpression;
}
}
}
+189
View File
@@ -0,0 +1,189 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class RulesMap {
public map: RulesBucket[];
public mapRowLength: number;
constructor() {
this.map = [];
this.mapRowLength = 0;
}
static create(rules: Rule[]): RulesMap {
var result = new RulesMap();
result.Initialize(rules);
return result;
}
public Initialize(rules: Rule[]) {
this.mapRowLength = SyntaxKind.LastToken + 1;
this.map = <any> new Array(this.mapRowLength * this.mapRowLength);//new Array<RulesBucket>(this.mapRowLength * this.mapRowLength);
// This array is used only during construction of the rulesbucket in the map
var rulesBucketConstructionStateList: RulesBucketConstructionState[] = <any> new Array(this.map.length);//new Array<RulesBucketConstructionState>(this.map.length);
this.FillRules(rules, rulesBucketConstructionStateList);
return this.map;
}
public FillRules(rules: Rule[], rulesBucketConstructionStateList: RulesBucketConstructionState[]): void {
rules.forEach((rule) => {
this.FillRule(rule, rulesBucketConstructionStateList);
});
}
private GetRuleBucketIndex(row: number, column: number): number {
var rulesBucketIndex = (row * this.mapRowLength) + column;
//Debug.Assert(rulesBucketIndex < this.map.Length, "Trying to access an index outside the array.");
return rulesBucketIndex;
}
private FillRule(rule: Rule, rulesBucketConstructionStateList: RulesBucketConstructionState[]): void {
var specificRule = rule.Descriptor.LeftTokenRange != Shared.TokenRange.Any &&
rule.Descriptor.RightTokenRange != Shared.TokenRange.Any;
rule.Descriptor.LeftTokenRange.GetTokens().forEach((left) => {
rule.Descriptor.RightTokenRange.GetTokens().forEach((right) => {
var rulesBucketIndex = this.GetRuleBucketIndex(left, right);
var rulesBucket = this.map[rulesBucketIndex];
if (rulesBucket == undefined) {
rulesBucket = this.map[rulesBucketIndex] = new RulesBucket();
}
rulesBucket.AddRule(rule, specificRule, rulesBucketConstructionStateList, rulesBucketIndex);
})
})
}
public GetRule(context: FormattingContext): Rule {
var bucketIndex = this.GetRuleBucketIndex(context.currentTokenSpan.kind, context.nextTokenSpan.kind);
var bucket = this.map[bucketIndex];
if (bucket != null) {
for (var i = 0, len = bucket.Rules().length; i < len; i++) {
var rule = bucket.Rules()[i];
if (rule.Operation.Context.InContext(context))
return rule;
}
}
return null;
}
}
var MaskBitSize = 5;
var Mask = 0x1f;
export enum RulesPosition {
IgnoreRulesSpecific = 0,
IgnoreRulesAny = MaskBitSize * 1,
ContextRulesSpecific = MaskBitSize * 2,
ContextRulesAny = MaskBitSize * 3,
NoContextRulesSpecific = MaskBitSize * 4,
NoContextRulesAny = MaskBitSize * 5
}
export class RulesBucketConstructionState {
private rulesInsertionIndexBitmap: number;
constructor() {
//// The Rules list contains all the inserted rules into a rulebucket in the following order:
//// 1- Ignore rules with specific token combination
//// 2- Ignore rules with any token combination
//// 3- Context rules with specific token combination
//// 4- Context rules with any token combination
//// 5- Non-context rules with specific token combination
//// 6- Non-context rules with any token combination
////
//// The member rulesInsertionIndexBitmap is used to describe the number of rules
//// in each sub-bucket (above) hence can be used to know the index of where to insert
//// the next rule. It's a bitmap which contains 6 different sections each is given 5 bits.
////
//// Example:
//// In order to insert a rule to the end of sub-bucket (3), we get the index by adding
//// the values in the bitmap segments 3rd, 2nd, and 1st.
this.rulesInsertionIndexBitmap = 0;
}
public GetInsertionIndex(maskPosition: RulesPosition): number {
var index = 0;
var pos = 0;
var indexBitmap = this.rulesInsertionIndexBitmap;
while (pos <= maskPosition) {
index += (indexBitmap & Mask);
indexBitmap >>= MaskBitSize;
pos += MaskBitSize;
}
return index;
}
public IncreaseInsertionIndex(maskPosition: RulesPosition): void {
var value = (this.rulesInsertionIndexBitmap >> maskPosition) & Mask;
value++;
Debug.assert((value & Mask) == value, "Adding more rules into the sub-bucket than allowed. Maximum allowed is 32 rules.");
var temp = this.rulesInsertionIndexBitmap & ~(Mask << maskPosition);
temp |= value << maskPosition;
this.rulesInsertionIndexBitmap = temp;
}
}
export class RulesBucket {
private rules: Rule[];
constructor() {
this.rules = [];
}
public Rules(): Rule[] {
return this.rules;
}
public AddRule(rule: Rule, specificTokens: boolean, constructionState: RulesBucketConstructionState[], rulesBucketIndex: number): void {
var position: RulesPosition;
if (rule.Operation.Action == RuleAction.Ignore) {
position = specificTokens ?
RulesPosition.IgnoreRulesSpecific :
RulesPosition.IgnoreRulesAny;
}
else if (!rule.Operation.Context.IsAny()) {
position = specificTokens ?
RulesPosition.ContextRulesSpecific :
RulesPosition.ContextRulesAny;
}
else {
position = specificTokens ?
RulesPosition.NoContextRulesSpecific :
RulesPosition.NoContextRulesAny;
}
var state = constructionState[rulesBucketIndex];
if (state === undefined) {
state = constructionState[rulesBucketIndex] = new RulesBucketConstructionState();
}
var index = state.GetInsertionIndex(position);
this.rules.splice(index, 0, rule);
state.IncreaseInsertionIndex(position);
}
}
}
+117
View File
@@ -0,0 +1,117 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
/// <reference path="formatting.ts"/>
module TypeScript.Services.Formatting {
export class RulesProvider {
private globalRules: Rules;
private options: ts.FormatCodeOptions;
private activeRules: Rule[];
private rulesMap: RulesMap;
constructor(private logger: TypeScript.Logger) {
this.globalRules = new Rules();
}
public getRuleName(rule: Rule): string {
return this.globalRules.getRuleName(rule);
}
public getRuleByName(name: string): Rule {
return this.globalRules[name];
}
public getRulesMap() {
return this.rulesMap;
}
public ensureUpToDate(options: ts.FormatCodeOptions) {
if (this.options == null || !ts.compareDataObjects(this.options, options)) {
var activeRules: Rule[] = TypeScript.timeFunction(this.logger, "RulesProvider: createActiveRules()", () => { return this.createActiveRules(options); });
var rulesMap: RulesMap = TypeScript.timeFunction(this.logger, "RulesProvider: RulesMap.create()", () => { return RulesMap.create(activeRules); });
this.activeRules = activeRules;
this.rulesMap = rulesMap;
this.options = ts.clone(options);
}
}
private createActiveRules(options: ts.FormatCodeOptions): Rule[] {
var rules = this.globalRules.HighPriorityCommonRules.slice(0);
if (options.InsertSpaceAfterCommaDelimiter) {
rules.push(this.globalRules.SpaceAfterComma);
}
else {
rules.push(this.globalRules.NoSpaceAfterComma);
}
if (options.InsertSpaceAfterFunctionKeywordForAnonymousFunctions) {
rules.push(this.globalRules.SpaceAfterAnonymousFunctionKeyword);
}
else {
rules.push(this.globalRules.NoSpaceAfterAnonymousFunctionKeyword);
}
if (options.InsertSpaceAfterKeywordsInControlFlowStatements) {
rules.push(this.globalRules.SpaceAfterKeywordInControl);
}
else {
rules.push(this.globalRules.NoSpaceAfterKeywordInControl);
}
if (options.InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis) {
rules.push(this.globalRules.SpaceAfterOpenParen);
rules.push(this.globalRules.SpaceBeforeCloseParen);
rules.push(this.globalRules.NoSpaceBetweenParens);
}
else {
rules.push(this.globalRules.NoSpaceAfterOpenParen);
rules.push(this.globalRules.NoSpaceBeforeCloseParen);
rules.push(this.globalRules.NoSpaceBetweenParens);
}
if (options.InsertSpaceAfterSemicolonInForStatements) {
rules.push(this.globalRules.SpaceAfterSemicolonInFor);
}
else {
rules.push(this.globalRules.NoSpaceAfterSemicolonInFor);
}
if (options.InsertSpaceBeforeAndAfterBinaryOperators) {
rules.push(this.globalRules.SpaceBeforeBinaryOperator);
rules.push(this.globalRules.SpaceAfterBinaryOperator);
}
else {
rules.push(this.globalRules.NoSpaceBeforeBinaryOperator);
rules.push(this.globalRules.NoSpaceAfterBinaryOperator);
}
if (options.PlaceOpenBraceOnNewLineForControlBlocks) {
rules.push(this.globalRules.NewLineBeforeOpenBraceInControl);
}
if (options.PlaceOpenBraceOnNewLineForFunctions) {
rules.push(this.globalRules.NewLineBeforeOpenBraceInFunction);
rules.push(this.globalRules.NewLineBeforeOpenBraceInTypeScriptDeclWithBlock);
}
rules = rules.concat(this.globalRules.LowPriorityCommonRules);
return rules;
}
}
}
@@ -0,0 +1,46 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class SingleTokenIndenter extends IndentationTrackingWalker {
private indentationAmount: number = null;
private indentationPosition: number;
constructor(indentationPosition: number, sourceUnit: SourceUnitSyntax, snapshot: ITextSnapshot, indentFirstToken: boolean, options: FormattingOptions) {
super(new TextSpan(indentationPosition, 1), sourceUnit, snapshot, indentFirstToken, options);
this.indentationPosition = indentationPosition;
}
public static getIndentationAmount(position: number, sourceUnit: SourceUnitSyntax, snapshot: ITextSnapshot, options: FormattingOptions): number {
var walker = new SingleTokenIndenter(position, sourceUnit, snapshot, true, options);
visitNodeOrToken(walker, sourceUnit);
return walker.indentationAmount;
}
public indentToken(token: ISyntaxToken, indentationAmount: number, commentIndentationAmount: number): void {
// Compute an indentation string for this token
if (token.fullWidth() === 0 || (this.indentationPosition - this.position() < token.leadingTriviaWidth())) {
// The position is in the leading trivia, use comment indentation
this.indentationAmount = commentIndentationAmount;
}
else {
this.indentationAmount = indentationAmount;
}
}
}
}
+30
View File
@@ -0,0 +1,30 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class SnapshotPoint {
constructor(public snapshot: ITextSnapshot, public position: number) {
}
public getContainingLine(): ITextSnapshotLine {
return this.snapshot.getLineFromPosition(this.position);
}
public add(offset: number): SnapshotPoint {
return new SnapshotPoint(this.snapshot, this.position + offset);
}
}
}
+28
View File
@@ -0,0 +1,28 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class TextEditInfo {
constructor(public position: number, public length: number, public replaceWith: string) {
}
public toString() {
return "[ position: " + this.position + ", length: " + this.length + ", replaceWith: '" + this.replaceWith + "' ]";
}
}
}
+84
View File
@@ -0,0 +1,84 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export interface ITextSnapshot {
getText(span: TextSpan): string;
getLineNumberFromPosition(position: number): number;
getLineFromPosition(position: number): ITextSnapshotLine;
getLineFromLineNumber(lineNumber: number): ITextSnapshotLine;
}
export class TextSnapshot implements ITextSnapshot {
private lines: TextSnapshotLine[];
constructor(private snapshot: ISimpleText) {
this.lines = [];
}
public getText(span: TextSpan): string {
return this.snapshot.substr(span.start(), span.length());
}
public getLineNumberFromPosition(position: number): number {
return this.snapshot.lineMap().getLineNumberFromPosition(position);
}
public getLineFromPosition(position: number): ITextSnapshotLine {
var lineNumber = this.getLineNumberFromPosition(position);
return this.getLineFromLineNumber(lineNumber);
}
public getLineFromLineNumber(lineNumber: number): ITextSnapshotLine {
var line = this.lines[lineNumber];
if (line === undefined) {
line = <TextSnapshotLine>this.getLineFromLineNumberWorker(lineNumber);
this.lines[lineNumber] = line;
}
return line;
}
private getLineFromLineNumberWorker(lineNumber: number): ITextSnapshotLine {
var lineMap = this.snapshot.lineMap().lineStarts();
var lineMapIndex = lineNumber; //Note: lineMap is 0-based
if (lineMapIndex < 0 || lineMapIndex >= lineMap.length)
throw new Error(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.Invalid_line_number_0, [lineMapIndex]));
var start = lineMap[lineMapIndex];
var end: number;
var endIncludingLineBreak: number;
var lineBreak = "";
if (lineMapIndex == lineMap.length) {
end = endIncludingLineBreak = this.snapshot.length();
}
else {
endIncludingLineBreak = (lineMapIndex >= lineMap.length - 1 ? this.snapshot.length() : lineMap[lineMapIndex + 1]);
for (var p = endIncludingLineBreak - 1; p >= start; p--) {
var c = this.snapshot.substr(p, 1);
//TODO: Other ones?
if (c != "\r" && c != "\n") {
break;
}
}
end = p + 1;
lineBreak = this.snapshot.substr(end, endIncludingLineBreak - end);
}
var result = new TextSnapshotLine(this, lineNumber, start, end, lineBreak);
return result;
}
}
}
@@ -0,0 +1,80 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export interface ITextSnapshotLine {
snapshot(): ITextSnapshot;
start(): SnapshotPoint;
startPosition(): number;
end(): SnapshotPoint;
endPosition(): number;
endIncludingLineBreak(): SnapshotPoint;
endIncludingLineBreakPosition(): number;
length(): number;
lineNumber(): number;
getText(): string;
}
export class TextSnapshotLine implements ITextSnapshotLine {
constructor(private _snapshot: ITextSnapshot, private _lineNumber: number, private _start: number, private _end: number, private _lineBreak: string) {
}
public snapshot() {
return this._snapshot;
}
public start() {
return new SnapshotPoint(this._snapshot, this._start);
}
public startPosition() {
return this._start;
}
public end() {
return new SnapshotPoint(this._snapshot, this._end);
}
public endPosition() {
return this._end;
}
public endIncludingLineBreak() {
return new SnapshotPoint(this._snapshot, this._end + this._lineBreak.length);
}
public endIncludingLineBreakPosition() {
return this._end + this._lineBreak.length;
}
public length() {
return this._end - this._start;
}
public lineNumber() {
return this._lineNumber;
}
public getText(): string {
return this._snapshot.getText(TextSpan.fromBounds(this._start, this._end));
}
}
}
+152
View File
@@ -0,0 +1,152 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export module Shared {
export interface ITokenAccess {
GetTokens(): SyntaxKind[];
Contains(token: SyntaxKind): boolean;
}
export class TokenRangeAccess implements ITokenAccess {
private tokens: SyntaxKind[];
constructor(from: SyntaxKind, to: SyntaxKind, except: SyntaxKind[]) {
this.tokens = [];
for (var token = from; token <= to; token++) {
if (except.indexOf(token) < 0) {
this.tokens.push(token);
}
}
}
public GetTokens(): SyntaxKind[] {
return this.tokens;
}
public Contains(token: SyntaxKind): boolean {
return this.tokens.indexOf(token) >= 0;
}
public toString(): string {
return "[tokenRangeStart=" + SyntaxKind[this.tokens[0]] + "," +
"tokenRangeEnd=" + SyntaxKind[this.tokens[this.tokens.length - 1]] + "]";
}
}
export class TokenValuesAccess implements ITokenAccess {
private tokens: SyntaxKind[];
constructor(tks: SyntaxKind[]) {
this.tokens = tks && tks.length ? tks : <SyntaxKind[]>[];
}
public GetTokens(): SyntaxKind[] {
return this.tokens;
}
public Contains(token: SyntaxKind): boolean {
return this.tokens.indexOf(token) >= 0;
}
}
export class TokenSingleValueAccess implements ITokenAccess {
constructor(public token: SyntaxKind) {
}
public GetTokens(): SyntaxKind[] {
return [this.token];
}
public Contains(tokenValue: SyntaxKind): boolean {
return tokenValue == this.token;
}
public toString(): string {
return "[singleTokenKind=" + SyntaxKind[this.token] + "]";
}
}
export class TokenAllAccess implements ITokenAccess {
public GetTokens(): SyntaxKind[] {
var result: SyntaxKind[] = [];
for (var token = SyntaxKind.FirstToken; token <= SyntaxKind.LastToken; token++) {
result.push(token);
}
return result;
}
public Contains(tokenValue: SyntaxKind): boolean {
return true;
}
public toString(): string {
return "[allTokens]";
}
}
export class TokenRange {
constructor(public tokenAccess: ITokenAccess) {
}
static FromToken(token: SyntaxKind): TokenRange {
return new TokenRange(new TokenSingleValueAccess(token));
}
static FromTokens(tokens: SyntaxKind[]): TokenRange {
return new TokenRange(new TokenValuesAccess(tokens));
}
static FromRange(f: SyntaxKind, to: SyntaxKind, except: SyntaxKind[] = []): TokenRange {
return new TokenRange(new TokenRangeAccess(f, to, except));
}
static AllTokens(): TokenRange {
return new TokenRange(new TokenAllAccess());
}
public GetTokens(): SyntaxKind[] {
return this.tokenAccess.GetTokens();
}
public Contains(token: SyntaxKind): boolean {
return this.tokenAccess.Contains(token);
}
public toString(): string {
return this.tokenAccess.toString();
}
static Any: TokenRange = TokenRange.AllTokens();
static AnyIncludingMultilineComments = TokenRange.FromTokens(TokenRange.Any.GetTokens().concat([SyntaxKind.MultiLineCommentTrivia]));
static Keywords = TokenRange.FromRange(SyntaxKind.FirstKeyword, SyntaxKind.LastKeyword);
static Operators = TokenRange.FromRange(SyntaxKind.SemicolonToken, SyntaxKind.SlashEqualsToken);
static BinaryOperators = TokenRange.FromRange(SyntaxKind.LessThanToken, SyntaxKind.SlashEqualsToken);
static BinaryKeywordOperators = TokenRange.FromTokens([SyntaxKind.InKeyword, SyntaxKind.InstanceOfKeyword]);
static ReservedKeywords = TokenRange.FromRange(SyntaxKind.FirstFutureReservedStrictKeyword, SyntaxKind.LastFutureReservedStrictKeyword);
static UnaryPrefixOperators = TokenRange.FromTokens([SyntaxKind.PlusPlusToken, SyntaxKind.MinusMinusToken, SyntaxKind.TildeToken, SyntaxKind.ExclamationToken]);
static UnaryPrefixExpressions = TokenRange.FromTokens([SyntaxKind.NumericLiteral, SyntaxKind.IdentifierName, SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.OpenBraceToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
static UnaryPreincrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
static UnaryPostincrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
static UnaryPredecrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
static UnaryPostdecrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
static Comments = TokenRange.FromTokens([SyntaxKind.SingleLineCommentTrivia, SyntaxKind.MultiLineCommentTrivia]);
static TypeNames = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.NumberKeyword, SyntaxKind.StringKeyword, SyntaxKind.BooleanKeyword, SyntaxKind.VoidKeyword, SyntaxKind.AnyKeyword]);
}
}
}
+25
View File
@@ -0,0 +1,25 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='formatting.ts' />
module TypeScript.Services.Formatting {
export class TokenSpan extends TextSpan {
constructor(public kind: SyntaxKind, start: number, length: number) {
super(start, length);
}
}
}
@@ -0,0 +1,355 @@
///<reference path='references.ts' />
module TypeScript.Services {
interface LexicalScope {
items: ts.Map<ts.NavigateToItem>;
itemNames: string[];
childScopes: ts.Map<LexicalScope>;
childScopeNames: string[];
}
export class GetScriptLexicalStructureWalker extends TypeScript.SyntaxWalker {
private nameStack: string[] = [];
private kindStack: string[] = [];
private parentScopes: LexicalScope[] = [];
private currentScope: LexicalScope;
private createScope(): LexicalScope {
return {
items: TypeScript.createIntrinsicsObject<ts.NavigateToItem>(),
childScopes: TypeScript.createIntrinsicsObject<LexicalScope>(),
childScopeNames: [],
itemNames: []
};
}
private pushNewContainerScope(containerName: string, kind: string): LexicalScope {
Debug.assert(containerName, "No scope name provided");
var key = kind + "+" + containerName;
this.nameStack.push(containerName);
this.kindStack.push(kind);
var parentScope = this.currentScope;
this.parentScopes.push(parentScope);
var scope = ts.lookUp(parentScope.childScopes, key);
if (!scope) {
scope = this.createScope()
parentScope.childScopes[key] = scope;
parentScope.childScopeNames.push(key);
}
this.currentScope = scope;
return parentScope;
}
private popScope() {
Debug.assert(this.parentScopes.length > 0, "No parent scopes to return to")
this.currentScope = this.parentScopes.pop();
this.kindStack.pop();
this.nameStack.pop();
}
constructor(private fileName: string) {
super();
this.currentScope = this.createScope();
}
private collectItems(items: ts.NavigateToItem[], scope = this.currentScope) {
scope.itemNames.forEach(item => {
items.push(scope.items[item]);
});
scope.childScopeNames.forEach(childScope => {
this.collectItems(items, scope.childScopes[childScope]);
});
}
static getListsOfAllScriptLexicalStructure(items: ts.NavigateToItem[], fileName: string, unit: TypeScript.SourceUnitSyntax) {
var visitor = new GetScriptLexicalStructureWalker(fileName);
visitNodeOrToken(visitor, unit);
visitor.collectItems(items);
}
private createItem(node: TypeScript.ISyntaxNode, modifiers: ISyntaxToken[], kind: string, name: string): void {
var key = kind + "+" + name;
if (ts.lookUp(this.currentScope.items, key) !== undefined) {
this.addAdditionalSpan(node, key);
return;
}
var item: ts.NavigateToItem = {
name: name,
kind: kind,
matchKind: ts.MatchKind.exact,
fileName: this.fileName,
kindModifiers: this.getKindModifiers(modifiers),
minChar: start(node),
limChar: end(node),
containerName: this.nameStack.join("."),
containerKind: this.kindStack.length === 0 ? "" : TypeScript.ArrayUtilities.last(this.kindStack),
};
this.currentScope.items[key] = item;
this.currentScope.itemNames.push(key);
}
private addAdditionalSpan(
node: TypeScript.ISyntaxNode,
key: string) {
var item = ts.lookUp(this.currentScope.items, key);
Debug.assert(item !== undefined);
var start = TypeScript.start(node);
var span: ts.SpanInfo = {
minChar: start,
limChar: start + width(node)
};
if (item.additionalSpans) {
item.additionalSpans.push(span);
}
else {
item.additionalSpans = [span];
}
}
private getKindModifiers(modifiers: TypeScript.ISyntaxToken[]): string {
var result: string[] = [];
for (var i = 0, n = modifiers.length; i < n; i++) {
result.push(modifiers[i].text());
}
return result.length > 0 ? result.join(',') : ts.ScriptElementKindModifier.none;
}
public visitModuleDeclaration(node: TypeScript.ModuleDeclarationSyntax): void {
var names = this.getModuleNames(node);
this.visitModuleDeclarationWorker(node, names, 0);
}
private visitModuleDeclarationWorker(node: TypeScript.ModuleDeclarationSyntax, names: string[], nameIndex: number): void {
if (nameIndex === names.length) {
// We're after all the module names, descend and process all children.
super.visitModuleDeclaration(node);
}
else {
var name = names[nameIndex];
var kind = ts.ScriptElementKind.moduleElement;
this.createItem(node, node.modifiers, kind, name);
this.pushNewContainerScope(name, kind);
this.visitModuleDeclarationWorker(node, names, nameIndex + 1);
this.popScope();
}
}
private getModuleNames(node: TypeScript.ModuleDeclarationSyntax): string[] {
var result: string[] = [];
if (node.stringLiteral) {
result.push(node.stringLiteral.text());
}
else {
this.getModuleNamesHelper(node.name, result);
}
return result;
}
private getModuleNamesHelper(name: TypeScript.INameSyntax, result: string[]): void {
if (name.kind() === TypeScript.SyntaxKind.QualifiedName) {
var qualifiedName = <TypeScript.QualifiedNameSyntax>name;
this.getModuleNamesHelper(qualifiedName.left, result);
result.push(qualifiedName.right.text());
}
else {
result.push((<TypeScript.ISyntaxToken>name).text());
}
}
public visitClassDeclaration(node: TypeScript.ClassDeclarationSyntax): void {
var name = node.identifier.text();
var kind = ts.ScriptElementKind.classElement;
this.createItem(node, node.modifiers, kind, name);
this.pushNewContainerScope(name, kind);
super.visitClassDeclaration(node);
this.popScope();
}
public visitInterfaceDeclaration(node: TypeScript.InterfaceDeclarationSyntax): void {
var name = node.identifier.text();
var kind = ts.ScriptElementKind.interfaceElement;
this.createItem(node, node.modifiers, kind, name);
this.pushNewContainerScope(name, kind);
super.visitInterfaceDeclaration(node);
this.popScope();
}
public visitObjectType(node: TypeScript.ObjectTypeSyntax): void {
// Ignore an object type if we aren't inside an interface declaration. We don't want
// to add some random object type's members to the nav bar.
if (node.parent.kind() === SyntaxKind.InterfaceDeclaration) {
super.visitObjectType(node);
}
}
public visitEnumDeclaration(node: TypeScript.EnumDeclarationSyntax): void {
var name = node.identifier.text();
var kind = ts.ScriptElementKind.enumElement;
this.createItem(node, node.modifiers, kind, name);
this.pushNewContainerScope(name, kind);
super.visitEnumDeclaration(node);
this.popScope();
}
public visitConstructorDeclaration(node: TypeScript.ConstructorDeclarationSyntax): void {
this.createItem(node, TypeScript.Syntax.emptyList<ISyntaxToken>(), ts.ScriptElementKind.constructorImplementationElement, "constructor");
// Search the parameter list of class properties
var parameters = node.callSignature.parameterList.parameters;
if (parameters) {
for (var i = 0, n = parameters.length; i < n; i++) {
var parameter = <ParameterSyntax>parameters[i];
Debug.assert(parameter.kind() === SyntaxKind.Parameter);
if (SyntaxUtilities.containsToken(parameter.modifiers, SyntaxKind.PublicKeyword) ||
SyntaxUtilities.containsToken(parameter.modifiers, SyntaxKind.PrivateKeyword)) {
this.createItem(node, parameter.modifiers, ts.ScriptElementKind.memberVariableElement, parameter.identifier.text());
}
}
}
// No need to descend into a constructor;
}
public visitMemberFunctionDeclaration(node: TypeScript.MemberFunctionDeclarationSyntax): void {
this.createItem(node, node.modifiers, ts.ScriptElementKind.memberFunctionElement, node.propertyName.text());
// No need to descend into a member function;
}
public visitGetAccessor(node: TypeScript.GetAccessorSyntax): void {
this.createItem(node, node.modifiers, ts.ScriptElementKind.memberGetAccessorElement, node.propertyName.text());
// No need to descend into a member accessor;
}
public visitSetAccessor(node: TypeScript.SetAccessorSyntax): void {
this.createItem(node, node.modifiers, ts.ScriptElementKind.memberSetAccessorElement, node.propertyName.text());
// No need to descend into a member accessor;
}
public visitVariableDeclarator(node: TypeScript.VariableDeclaratorSyntax): void {
var modifiers = node.parent.kind() === SyntaxKind.MemberVariableDeclaration
? (<MemberVariableDeclarationSyntax>node.parent).modifiers
: TypeScript.Syntax.emptyList<ISyntaxToken>();
var kind = node.parent.kind() === SyntaxKind.MemberVariableDeclaration
? ts.ScriptElementKind.memberVariableElement
: ts.ScriptElementKind.variableElement;
this.createItem(node, modifiers, kind, node.propertyName.text());
// No need to descend into a variable declarator;
}
public visitIndexSignature(node: TypeScript.IndexSignatureSyntax): void {
this.createItem(node, TypeScript.Syntax.emptyList<ISyntaxToken>(), ts.ScriptElementKind.indexSignatureElement, "[]");
// No need to descend into an index signature;
}
public visitEnumElement(node: TypeScript.EnumElementSyntax): void {
this.createItem(node, TypeScript.Syntax.emptyList<ISyntaxToken>(), ts.ScriptElementKind.memberVariableElement, node.propertyName.text());
// No need to descend into an enum element;
}
public visitCallSignature(node: TypeScript.CallSignatureSyntax): void {
this.createItem(node, TypeScript.Syntax.emptyList<ISyntaxToken>(), ts.ScriptElementKind.callSignatureElement, "()");
// No need to descend into a call signature;
}
public visitConstructSignature(node: TypeScript.ConstructSignatureSyntax): void {
this.createItem(node, TypeScript.Syntax.emptyList<ISyntaxToken>(), ts.ScriptElementKind.constructSignatureElement, "new()");
// No need to descend into a construct signature;
}
public visitMethodSignature(node: TypeScript.MethodSignatureSyntax): void {
this.createItem(node, TypeScript.Syntax.emptyList<ISyntaxToken>(), ts.ScriptElementKind.memberFunctionElement, node.propertyName.text());
// No need to descend into a method signature;
}
public visitPropertySignature(node: TypeScript.PropertySignatureSyntax): void {
this.createItem(node, TypeScript.Syntax.emptyList<ISyntaxToken>(), ts.ScriptElementKind.memberVariableElement, node.propertyName.text());
// No need to descend into a property signature;
}
public visitFunctionDeclaration(node: TypeScript.FunctionDeclarationSyntax): void {
// in the case of:
// declare function
// the parser will synthesize an identifier.
// we shouldn't add an unnamed function declaration
if (width(node.identifier) > 0) {
this.createItem(node, node.modifiers, ts.ScriptElementKind.functionElement, node.identifier.text());
}
// No need to descend into a function declaration;
}
// Common statement types. Don't even bother walking into them as we'll never find anything
// inside that we'd put in the navbar.
public visitBlock(node: TypeScript.BlockSyntax): void {
}
public visitIfStatement(node: TypeScript.IfStatementSyntax): void {
}
public visitExpressionStatement(node: TypeScript.ExpressionStatementSyntax): void {
}
public visitThrowStatement(node: TypeScript.ThrowStatementSyntax): void {
}
public visitReturnStatement(node: TypeScript.ReturnStatementSyntax): void {
}
public visitSwitchStatement(node: TypeScript.SwitchStatementSyntax): void {
}
public visitWithStatement(node: TypeScript.WithStatementSyntax): void {
}
public visitTryStatement(node: TypeScript.TryStatementSyntax): void {
}
public visitLabeledStatement(node: TypeScript.LabeledStatementSyntax): void {
}
}
}
+155
View File
@@ -0,0 +1,155 @@
///<reference path='references.ts' />
module TypeScript.Indentation {
export function columnForEndOfTokenAtPosition(syntaxTree: SyntaxTree, position: number, options: FormattingOptions): number {
var token = findToken(syntaxTree.sourceUnit(), position);
return columnForStartOfTokenAtPosition(syntaxTree, position, options) + width(token);
}
export function columnForStartOfTokenAtPosition(syntaxTree: SyntaxTree, position: number, options: FormattingOptions): number {
var token = findToken(syntaxTree.sourceUnit(), position);
// Walk backward from this token until we find the first token in the line. For each token
// we see (that is not the first tokem in line), push the entirety of the text into the text
// array. Then, for the first token, add its text (without its leading trivia) to the text
// array. i.e. if we have:
//
// var foo = a => bar();
//
// And we want the column for the start of 'bar', then we'll add the underlinded portions to
// the text array:
//
// var foo = a => bar();
// _
// __
// __
// ____
// ____
var firstTokenInLine = Syntax.firstTokenInLineContainingPosition(syntaxTree, token.fullStart());
var leadingTextInReverse: string[] = [];
var current = token;
while (current !== firstTokenInLine) {
current = previousToken(current);
if (current === firstTokenInLine) {
// We're at the first token in teh line.
// We don't want the leading trivia for this token. That will be taken care of in
// columnForFirstNonWhitespaceCharacterInLine. So just push the trailing trivia
// and then the token text.
leadingTextInReverse.push(current.trailingTrivia().fullText());
leadingTextInReverse.push(current.text());
}
else {
// We're at an intermediate token on the line. Just push all its text into the array.
leadingTextInReverse.push(current.fullText());
}
}
// Now, add all trivia to the start of the line on the first token in the list.
collectLeadingTriviaTextToStartOfLine(firstTokenInLine, leadingTextInReverse);
return columnForLeadingTextInReverse(leadingTextInReverse, options);
}
export function columnForStartOfFirstTokenInLineContainingPosition(syntaxTree: SyntaxTree, position: number, options: FormattingOptions): number {
// Walk backward through the tokens until we find the first one on the line.
var firstTokenInLine = Syntax.firstTokenInLineContainingPosition(syntaxTree, position);
var leadingTextInReverse: string[] = [];
// Now, add all trivia to the start of the line on the first token in the list.
collectLeadingTriviaTextToStartOfLine(firstTokenInLine, leadingTextInReverse);
return columnForLeadingTextInReverse(leadingTextInReverse, options);
}
// Collect all the trivia that precedes this token. Stopping when we hit a newline trivia
// or a multiline comment that spans multiple lines. This is meant to be called on the first
// token in a line.
function collectLeadingTriviaTextToStartOfLine(firstTokenInLine: ISyntaxToken,
leadingTextInReverse: string[]) {
var leadingTrivia = firstTokenInLine.leadingTrivia();
for (var i = leadingTrivia.count() - 1; i >= 0; i--) {
var trivia = leadingTrivia.syntaxTriviaAt(i);
if (trivia.kind() === SyntaxKind.NewLineTrivia) {
break;
}
if (trivia.kind() === SyntaxKind.MultiLineCommentTrivia) {
var lineSegments = Syntax.splitMultiLineCommentTriviaIntoMultipleLines(trivia);
leadingTextInReverse.push(ArrayUtilities.last(lineSegments));
if (lineSegments.length > 0) {
// This multiline comment actually spanned multiple lines. So we're done.
break;
}
// It was only on a single line, so keep on going.
}
leadingTextInReverse.push(trivia.fullText());
}
}
function columnForLeadingTextInReverse(leadingTextInReverse: string[],
options: FormattingOptions): number {
var column = 0;
// walk backwards. This means we're actually walking forward from column 0 to the start of
// the token.
for (var i = leadingTextInReverse.length - 1; i >= 0; i--) {
var text = leadingTextInReverse[i];
column = columnForPositionInStringWorker(text, text.length, column, options);
}
return column;
}
// Returns the column that this input string ends at (assuming it starts at column 0).
export function columnForPositionInString(input: string, position: number, options: FormattingOptions): number {
return columnForPositionInStringWorker(input, position, 0, options);
}
function columnForPositionInStringWorker(input: string, position: number, startColumn: number, options: FormattingOptions): number {
var column = startColumn;
var spacesPerTab = options.spacesPerTab;
for (var j = 0; j < position; j++) {
var ch = input.charCodeAt(j);
if (ch === CharacterCodes.tab) {
column += spacesPerTab - column % spacesPerTab;
}
else {
column++;
}
}
return column;
}
export function indentationString(column: number, options: FormattingOptions): string {
var numberOfTabs = 0;
var numberOfSpaces = Math.max(0, column);
if (options.useTabs) {
numberOfTabs = Math.floor(column / options.spacesPerTab);
numberOfSpaces -= numberOfTabs * options.spacesPerTab;
}
return StringUtilities.repeat('\t', numberOfTabs) +
StringUtilities.repeat(' ', numberOfSpaces);
}
export function firstNonWhitespacePosition(value: string): number {
for (var i = 0; i < value.length; i++) {
var ch = value.charCodeAt(i);
if (!CharacterInfo.isWhitespace(ch)) {
return i;
}
}
return value.length;
}
}
+109
View File
@@ -0,0 +1,109 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///<reference path='references.ts' />
module TypeScript.Services {
export class OutliningElementsCollector extends TypeScript.DepthLimitedWalker {
// The maximum depth for collecting spans; this will cause us to miss deeply nested function/modules spans,
// but will guarantee performance will not be closely tied to tree depth.
private static MaximumDepth: number = 10;
private inObjectLiteralExpression: boolean = false;
private elements: TypeScript.TextSpan[] = [];
constructor() {
super(OutliningElementsCollector.MaximumDepth);
}
public visitClassDeclaration(node: TypeScript.ClassDeclarationSyntax): void {
this.addOutlineRange(node, node.openBraceToken, node.closeBraceToken);
super.visitClassDeclaration(node);
}
public visitInterfaceDeclaration(node: TypeScript.InterfaceDeclarationSyntax): void {
this.addOutlineRange(node, node.body.openBraceToken, node.body.closeBraceToken);
super.visitInterfaceDeclaration(node);
}
public visitModuleDeclaration(node: TypeScript.ModuleDeclarationSyntax): void {
this.addOutlineRange(node, node.openBraceToken, node.closeBraceToken);
super.visitModuleDeclaration(node);
}
public visitEnumDeclaration(node: TypeScript.EnumDeclarationSyntax): void {
this.addOutlineRange(node, node.openBraceToken, node.closeBraceToken);
super.visitEnumDeclaration(node);
}
public visitFunctionDeclaration(node: TypeScript.FunctionDeclarationSyntax): void {
this.addOutlineRange(node, node.block, node.block);
super.visitFunctionDeclaration(node);
}
public visitFunctionExpression(node: TypeScript.FunctionExpressionSyntax): void {
this.addOutlineRange(node, node.block, node.block);
super.visitFunctionExpression(node);
}
public visitConstructorDeclaration(node: TypeScript.ConstructorDeclarationSyntax): void {
this.addOutlineRange(node, node.block, node.block);
super.visitConstructorDeclaration(node);
}
public visitMemberFunctionDeclaration(node: TypeScript.MemberFunctionDeclarationSyntax): void {
this.addOutlineRange(node, node.block, node.block);
super.visitMemberFunctionDeclaration(node);
}
public visitGetAccessor(node: TypeScript.GetAccessorSyntax): void {
if (!this.inObjectLiteralExpression) {
this.addOutlineRange(node, node.block, node.block);
}
super.visitGetAccessor(node);
}
public visitSetAccessor(node: TypeScript.SetAccessorSyntax): void {
if (!this.inObjectLiteralExpression) {
this.addOutlineRange(node, node.block, node.block);
}
super.visitSetAccessor(node);
}
public visitObjectLiteralExpression(node: TypeScript.ObjectLiteralExpressionSyntax): void {
var savedInObjectLiteralExpression = this.inObjectLiteralExpression;
this.inObjectLiteralExpression = true;
super.visitObjectLiteralExpression(node);
this.inObjectLiteralExpression = savedInObjectLiteralExpression;
}
private addOutlineRange(node: TypeScript.ISyntaxNode, startElement: TypeScript.ISyntaxNodeOrToken, endElement: TypeScript.ISyntaxNodeOrToken) {
if (startElement && endElement && !isShared(startElement) && !isShared(endElement)) {
// Compute the position
var start = TypeScript.start(startElement);
var end = TypeScript.end(endElement);
// Push the new range
this.elements.push(TypeScript.TextSpan.fromBounds(start, end));
}
}
public static collectElements(node: TypeScript.SourceUnitSyntax): TypeScript.TextSpan[] {
var collector = new OutliningElementsCollector();
visitNodeOrToken(collector, node);
return collector.elements;
}
}
}
+26
View File
@@ -0,0 +1,26 @@
/////<reference path='es5compat.ts' />
/////<reference path='..\compiler\typescript.ts' />
//// document.ts depends on incrementalParser.ts being run first.
/////<reference path='..\compiler\syntax\incrementalParser.ts' />
/////<reference path='document.ts' />
/////<reference path='syntaxUtilities.generated.ts' />
/////<reference path='coreServices.ts' />
/////<reference path='classifier.ts' />
/////<reference path='compilerState.ts' />
/////<reference path='indentation.ts' />
/////<reference path='languageService.ts' />
/////<reference path='completionHelpers.ts' />
/////<reference path='keywordCompletions.ts' />
/////<reference path='signatureInfoHelpers.ts' />
/////<reference path='completionSession.ts' />
/////<reference path='pullLanguageService.ts' />
/////<reference path='findReferenceHelpers.ts' />
/////<reference path='shims.ts' />
/////<reference path='formatting\formatting.ts' />
/////<reference path='outliningElementsCollector.ts' />
/////<reference path='braceMatcher.ts' />
/////<reference path='indenter.ts' />
/////<reference path='breakpoints.ts' />
/////<reference path='getScriptLexicalStructureWalker.ts' />
@@ -0,0 +1,445 @@
// <auto-generated />
module TypeScript {
export var DiagnosticCode = {
error_TS_0_1: "error TS{0}: {1}",
warning_TS_0_1: "warning TS{0}: {1}",
Unrecognized_escape_sequence: "Unrecognized escape sequence.",
Unexpected_character_0: "Unexpected character {0}.",
Missing_close_quote_character: "Missing close quote character.",
Identifier_expected: "Identifier expected.",
_0_keyword_expected: "'{0}' keyword expected.",
_0_expected: "'{0}' expected.",
Identifier_expected_0_is_a_keyword: "Identifier expected; '{0}' is a keyword.",
Automatic_semicolon_insertion_not_allowed: "Automatic semicolon insertion not allowed.",
Unexpected_token_0_expected: "Unexpected token; '{0}' expected.",
Trailing_comma_not_allowed: "Trailing comma not allowed.",
AsteriskSlash_expected: "'*/' expected.",
public_or_private_modifier_must_precede_static: "'public' or 'private' modifier must precede 'static'.",
Unexpected_token: "Unexpected token.",
Catch_clause_parameter_cannot_have_a_type_annotation: "Catch clause parameter cannot have a type annotation.",
A_rest_parameter_must_be_last_in_a_parameter_list: "A rest parameter must be last in a parameter list.",
Parameter_cannot_have_question_mark_and_initializer: "Parameter cannot have question mark and initializer.",
A_required_parameter_cannot_follow_an_optional_parameter: "A required parameter cannot follow an optional parameter.",
Index_signatures_cannot_have_rest_parameters: "Index signatures cannot have rest parameters.",
Index_signature_parameter_cannot_have_accessibility_modifiers: "Index signature parameter cannot have accessibility modifiers.",
Index_signature_parameter_cannot_have_a_question_mark: "Index signature parameter cannot have a question mark.",
Index_signature_parameter_cannot_have_an_initializer: "Index signature parameter cannot have an initializer.",
Index_signature_must_have_a_type_annotation: "Index signature must have a type annotation.",
Index_signature_parameter_must_have_a_type_annotation: "Index signature parameter must have a type annotation.",
Index_signature_parameter_type_must_be_string_or_number: "Index signature parameter type must be 'string' or 'number'.",
extends_clause_already_seen: "'extends' clause already seen.",
extends_clause_must_precede_implements_clause: "'extends' clause must precede 'implements' clause.",
Classes_can_only_extend_a_single_class: "Classes can only extend a single class.",
implements_clause_already_seen: "'implements' clause already seen.",
Accessibility_modifier_already_seen: "Accessibility modifier already seen.",
_0_modifier_must_precede_1_modifier: "'{0}' modifier must precede '{1}' modifier.",
_0_modifier_already_seen: "'{0}' modifier already seen.",
_0_modifier_cannot_appear_on_a_class_element: "'{0}' modifier cannot appear on a class element.",
Interface_declaration_cannot_have_implements_clause: "Interface declaration cannot have 'implements' clause.",
super_invocation_cannot_have_type_arguments: "'super' invocation cannot have type arguments.",
Only_ambient_modules_can_use_quoted_names: "Only ambient modules can use quoted names.",
Statements_are_not_allowed_in_ambient_contexts: "Statements are not allowed in ambient contexts.",
A_function_implementation_cannot_be_declared_in_an_ambient_context: "A function implementation cannot be declared in an ambient context.",
A_declare_modifier_cannot_be_used_in_an_already_ambient_context: "A 'declare' modifier cannot be used in an already ambient context.",
Initializers_are_not_allowed_in_ambient_contexts: "Initializers are not allowed in ambient contexts.",
_0_modifier_cannot_appear_on_a_module_element: "'{0}' modifier cannot appear on a module element.",
A_declare_modifier_cannot_be_used_with_an_interface_declaration: "A 'declare' modifier cannot be used with an interface declaration.",
A_declare_modifier_is_required_for_a_top_level_declaration_in_a_d_ts_file: "A 'declare' modifier is required for a top level declaration in a .d.ts file.",
A_rest_parameter_cannot_be_optional: "A rest parameter cannot be optional.",
A_rest_parameter_cannot_have_an_initializer: "A rest parameter cannot have an initializer.",
set_accessor_must_have_exactly_one_parameter: "'set' accessor must have exactly one parameter.",
set_accessor_parameter_cannot_be_optional: "'set' accessor parameter cannot be optional.",
set_accessor_parameter_cannot_have_an_initializer: "'set' accessor parameter cannot have an initializer.",
set_accessor_cannot_have_rest_parameter: "'set' accessor cannot have rest parameter.",
get_accessor_cannot_have_parameters: "'get' accessor cannot have parameters.",
Modifiers_cannot_appear_here: "Modifiers cannot appear here.",
Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher: "Accessors are only available when targeting ECMAScript 5 and higher.",
Enum_member_must_have_initializer: "Enum member must have initializer.",
Export_assignment_cannot_be_used_in_internal_modules: "Export assignment cannot be used in internal modules.",
Ambient_enum_elements_can_only_have_integer_literal_initializers: "Ambient enum elements can only have integer literal initializers.",
module_class_interface_enum_import_or_statement: "module, class, interface, enum, import or statement",
constructor_function_accessor_or_variable: "constructor, function, accessor or variable",
statement: "statement",
case_or_default_clause: "case or default clause",
identifier: "identifier",
call_construct_index_property_or_function_signature: "call, construct, index, property or function signature",
expression: "expression",
type_name: "type name",
property_or_accessor: "property or accessor",
parameter: "parameter",
type: "type",
type_parameter: "type parameter",
A_declare_modifier_cannot_be_used_with_an_import_declaration: "A 'declare' modifier cannot be used with an import declaration.",
Invalid_reference_directive_syntax: "Invalid 'reference' directive syntax.",
Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher: "Octal literals are not available when targeting ECMAScript 5 and higher.",
Accessors_are_not_allowed_in_ambient_contexts: "Accessors are not allowed in ambient contexts.",
_0_modifier_cannot_appear_on_a_constructor_declaration: "'{0}' modifier cannot appear on a constructor declaration.",
_0_modifier_cannot_appear_on_a_parameter: "'{0}' modifier cannot appear on a parameter.",
Only_a_single_variable_declaration_is_allowed_in_a_for_in_statement: "Only a single variable declaration is allowed in a 'for...in' statement.",
Type_parameters_cannot_appear_on_a_constructor_declaration: "Type parameters cannot appear on a constructor declaration.",
Type_annotation_cannot_appear_on_a_constructor_declaration: "Type annotation cannot appear on a constructor declaration.",
Type_parameters_cannot_appear_on_an_accessor: "Type parameters cannot appear on an accessor.",
Type_annotation_cannot_appear_on_a_set_accessor: "Type annotation cannot appear on a 'set' accessor.",
Index_signature_must_have_exactly_one_parameter: "Index signature must have exactly one parameter.",
_0_list_cannot_be_empty: "'{0}' list cannot be empty.",
variable_declaration: "variable declaration",
type_argument: "type argument",
Invalid_use_of_0_in_strict_mode: "Invalid use of '{0}' in strict mode.",
with_statements_are_not_allowed_in_strict_mode: "'with' statements are not allowed in strict mode.",
delete_cannot_be_called_on_an_identifier_in_strict_mode: "'delete' cannot be called on an identifier in strict mode.",
Invalid_left_hand_side_in_for_in_statement: "Invalid left-hand side in 'for...in' statement.",
continue_statement_can_only_be_used_within_an_enclosing_iteration_statement: "'continue' statement can only be used within an enclosing iteration statement.",
break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement: "'break' statement can only be used within an enclosing iteration or switch statement.",
Jump_target_not_found: "Jump target not found.",
Jump_target_cannot_cross_function_boundary: "Jump target cannot cross function boundary.",
return_statement_must_be_contained_within_a_function_body: "'return' statement must be contained within a function body.",
Expression_expected: "Expression expected.",
Type_expected: "Type expected.",
Duplicate_identifier_0: "Duplicate identifier '{0}'.",
The_name_0_does_not_exist_in_the_current_scope: "The name '{0}' does not exist in the current scope.",
The_name_0_does_not_refer_to_a_value: "The name '{0}' does not refer to a value.",
super_can_only_be_used_inside_a_class_instance_method: "'super' can only be used inside a class instance method.",
The_left_hand_side_of_an_assignment_expression_must_be_a_variable_property_or_indexer: "The left-hand side of an assignment expression must be a variable, property or indexer.",
Value_of_type_0_is_not_callable_Did_you_mean_to_include_new: "Value of type '{0}' is not callable. Did you mean to include 'new'?",
Value_of_type_0_is_not_callable: "Value of type '{0}' is not callable.",
Value_of_type_0_is_not_newable: "Value of type '{0}' is not newable.",
An_index_expression_argument_must_be_string_number_or_any: "An index expression argument must be 'string', 'number', or 'any'.",
Operator_0_cannot_be_applied_to_types_1_and_2: "Operator '{0}' cannot be applied to types '{1}' and '{2}'.",
Type_0_is_not_assignable_to_type_1: "Type '{0}' is not assignable to type '{1}'.",
Type_0_is_not_assignable_to_type_1_NL_2: "Type '{0}' is not assignable to type '{1}':{NL}{2}",
Expected_var_class_interface_or_module: "Expected var, class, interface, or module.",
Getter_0_already_declared: "Getter '{0}' already declared.",
Setter_0_already_declared: "Setter '{0}' already declared.",
Exported_class_0_extends_private_class_1: "Exported class '{0}' extends private class '{1}'.",
Exported_class_0_implements_private_interface_1: "Exported class '{0}' implements private interface '{1}'.",
Exported_interface_0_extends_private_interface_1: "Exported interface '{0}' extends private interface '{1}'.",
Exported_class_0_extends_class_from_inaccessible_module_1: "Exported class '{0}' extends class from inaccessible module {1}.",
Exported_class_0_implements_interface_from_inaccessible_module_1: "Exported class '{0}' implements interface from inaccessible module {1}.",
Exported_interface_0_extends_interface_from_inaccessible_module_1: "Exported interface '{0}' extends interface from inaccessible module {1}.",
Public_static_property_0_of_exported_class_has_or_is_using_private_type_1: "Public static property '{0}' of exported class has or is using private type '{1}'.",
Public_property_0_of_exported_class_has_or_is_using_private_type_1: "Public property '{0}' of exported class has or is using private type '{1}'.",
Property_0_of_exported_interface_has_or_is_using_private_type_1: "Property '{0}' of exported interface has or is using private type '{1}'.",
Exported_variable_0_has_or_is_using_private_type_1: "Exported variable '{0}' has or is using private type '{1}'.",
Public_static_property_0_of_exported_class_is_using_inaccessible_module_1: "Public static property '{0}' of exported class is using inaccessible module {1}.",
Public_property_0_of_exported_class_is_using_inaccessible_module_1: "Public property '{0}' of exported class is using inaccessible module {1}.",
Property_0_of_exported_interface_is_using_inaccessible_module_1: "Property '{0}' of exported interface is using inaccessible module {1}.",
Exported_variable_0_is_using_inaccessible_module_1: "Exported variable '{0}' is using inaccessible module {1}.",
Parameter_0_of_constructor_from_exported_class_has_or_is_using_private_type_1: "Parameter '{0}' of constructor from exported class has or is using private type '{1}'.",
Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_private_type_1: "Parameter '{0}' of public static property setter from exported class has or is using private type '{1}'.",
Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_private_type_1: "Parameter '{0}' of public property setter from exported class has or is using private type '{1}'.",
Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_type_1: "Parameter '{0}' of constructor signature from exported interface has or is using private type '{1}'.",
Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_type_1: "Parameter '{0}' of call signature from exported interface has or is using private type '{1}'.",
Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_type_1: "Parameter '{0}' of public static method from exported class has or is using private type '{1}'.",
Parameter_0_of_public_method_from_exported_class_has_or_is_using_private_type_1: "Parameter '{0}' of public method from exported class has or is using private type '{1}'.",
Parameter_0_of_method_from_exported_interface_has_or_is_using_private_type_1: "Parameter '{0}' of method from exported interface has or is using private type '{1}'.",
Parameter_0_of_exported_function_has_or_is_using_private_type_1: "Parameter '{0}' of exported function has or is using private type '{1}'.",
Parameter_0_of_constructor_from_exported_class_is_using_inaccessible_module_1: "Parameter '{0}' of constructor from exported class is using inaccessible module {1}.",
Parameter_0_of_public_static_property_setter_from_exported_class_is_using_inaccessible_module_1: "Parameter '{0}' of public static property setter from exported class is using inaccessible module {1}.",
Parameter_0_of_public_property_setter_from_exported_class_is_using_inaccessible_module_1: "Parameter '{0}' of public property setter from exported class is using inaccessible module {1}.",
Parameter_0_of_constructor_signature_from_exported_interface_is_using_inaccessible_module_1: "Parameter '{0}' of constructor signature from exported interface is using inaccessible module {1}.",
Parameter_0_of_call_signature_from_exported_interface_is_using_inaccessible_module_1: "Parameter '{0}' of call signature from exported interface is using inaccessible module {1}",
Parameter_0_of_public_static_method_from_exported_class_is_using_inaccessible_module_1: "Parameter '{0}' of public static method from exported class is using inaccessible module {1}.",
Parameter_0_of_public_method_from_exported_class_is_using_inaccessible_module_1: "Parameter '{0}' of public method from exported class is using inaccessible module {1}.",
Parameter_0_of_method_from_exported_interface_is_using_inaccessible_module_1: "Parameter '{0}' of method from exported interface is using inaccessible module {1}.",
Parameter_0_of_exported_function_is_using_inaccessible_module_1: "Parameter '{0}' of exported function is using inaccessible module {1}.",
Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_private_type_0: "Return type of public static property getter from exported class has or is using private type '{0}'.",
Return_type_of_public_property_getter_from_exported_class_has_or_is_using_private_type_0: "Return type of public property getter from exported class has or is using private type '{0}'.",
Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_private_type_0: "Return type of constructor signature from exported interface has or is using private type '{0}'.",
Return_type_of_call_signature_from_exported_interface_has_or_is_using_private_type_0: "Return type of call signature from exported interface has or is using private type '{0}'.",
Return_type_of_index_signature_from_exported_interface_has_or_is_using_private_type_0: "Return type of index signature from exported interface has or is using private type '{0}'.",
Return_type_of_public_static_method_from_exported_class_has_or_is_using_private_type_0: "Return type of public static method from exported class has or is using private type '{0}'.",
Return_type_of_public_method_from_exported_class_has_or_is_using_private_type_0: "Return type of public method from exported class has or is using private type '{0}'.",
Return_type_of_method_from_exported_interface_has_or_is_using_private_type_0: "Return type of method from exported interface has or is using private type '{0}'.",
Return_type_of_exported_function_has_or_is_using_private_type_0: "Return type of exported function has or is using private type '{0}'.",
Return_type_of_public_static_property_getter_from_exported_class_is_using_inaccessible_module_0: "Return type of public static property getter from exported class is using inaccessible module {0}.",
Return_type_of_public_property_getter_from_exported_class_is_using_inaccessible_module_0: "Return type of public property getter from exported class is using inaccessible module {0}.",
Return_type_of_constructor_signature_from_exported_interface_is_using_inaccessible_module_0: "Return type of constructor signature from exported interface is using inaccessible module {0}.",
Return_type_of_call_signature_from_exported_interface_is_using_inaccessible_module_0: "Return type of call signature from exported interface is using inaccessible module {0}.",
Return_type_of_index_signature_from_exported_interface_is_using_inaccessible_module_0: "Return type of index signature from exported interface is using inaccessible module {0}.",
Return_type_of_public_static_method_from_exported_class_is_using_inaccessible_module_0: "Return type of public static method from exported class is using inaccessible module {0}.",
Return_type_of_public_method_from_exported_class_is_using_inaccessible_module_0: "Return type of public method from exported class is using inaccessible module {0}.",
Return_type_of_method_from_exported_interface_is_using_inaccessible_module_0: "Return type of method from exported interface is using inaccessible module {0}.",
Return_type_of_exported_function_is_using_inaccessible_module_0: "Return type of exported function is using inaccessible module {0}.",
new_T_cannot_be_used_to_create_an_array_Use_new_Array_T_instead: "'new T[]' cannot be used to create an array. Use 'new Array<T>()' instead.",
A_parameter_list_must_follow_a_generic_type_argument_list_expected: "A parameter list must follow a generic type argument list. '(' expected.",
Multiple_constructor_implementations_are_not_allowed: "Multiple constructor implementations are not allowed.",
Cannot_find_external_module_0: "Cannot find external module '{0}'.",
Module_cannot_be_aliased_to_a_non_module_type: "Module cannot be aliased to a non-module type.",
A_class_may_only_extend_another_class: "A class may only extend another class.",
A_class_may_only_implement_another_class_or_interface: "A class may only implement another class or interface.",
An_interface_may_only_extend_a_class_or_another_interface: "An interface may only extend a class or another interface.",
Unable_to_resolve_type: "Unable to resolve type.",
Unable_to_resolve_type_of_0: "Unable to resolve type of '{0}'.",
Unable_to_resolve_type_parameter_constraint: "Unable to resolve type parameter constraint.",
Type_parameter_constraint_cannot_be_a_primitive_type: "Type parameter constraint cannot be a primitive type.",
Supplied_parameters_do_not_match_any_signature_of_call_target: "Supplied parameters do not match any signature of call target.",
Supplied_parameters_do_not_match_any_signature_of_call_target_NL_0: "Supplied parameters do not match any signature of call target:{NL}{0}",
Cannot_use_new_with_an_expression_whose_type_lacks_a_signature: "Cannot use 'new' with an expression whose type lacks a signature.",
Only_a_void_function_can_be_called_with_the_new_keyword: "Only a void function can be called with the 'new' keyword.",
Could_not_select_overload_for_new_expression: "Could not select overload for 'new' expression.",
Type_0_does_not_satisfy_the_constraint_1: "Type '{0}' does not satisfy the constraint '{1}'.",
Could_not_select_overload_for_call_expression: "Could not select overload for 'call' expression.",
Cannot_invoke_an_expression_whose_type_lacks_a_call_signature: "Cannot invoke an expression whose type lacks a call signature.",
Calls_to_super_are_only_valid_inside_a_class: "Calls to 'super' are only valid inside a class.",
Generic_type_0_requires_1_type_argument_s: "Generic type '{0}' requires {1} type argument(s).",
Type_of_array_literal_cannot_be_determined_Best_common_type_could_not_be_found_for_array_elements: "Type of array literal cannot be determined. Best common type could not be found for array elements.",
Could_not_find_enclosing_symbol_for_dotted_name_0: "Could not find enclosing symbol for dotted name '{0}'.",
Property_0_does_not_exist_on_value_of_type_1: "Property '{0}' does not exist on value of type '{1}'.",
Cannot_find_name_0: "Cannot find name '{0}'.",
get_and_set_accessor_must_have_the_same_type: "'get' and 'set' accessor must have the same type.",
this_cannot_be_referenced_in_current_location: "'this' cannot be referenced in current location.",
Static_members_cannot_reference_class_type_parameters: "Static members cannot reference class type parameters.",
Type_0_recursively_references_itself_as_a_base_type: "Type '{0}' recursively references itself as a base type.",
super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class: "'super' property access is permitted only in a constructor, member function, or member accessor of a derived class.",
super_can_only_be_referenced_in_a_derived_class: "'super' can only be referenced in a derived class.",
A_super_call_must_be_the_first_statement_in_the_constructor_when_a_class_contains_initialized_properties_or_has_parameter_properties: "A 'super' call must be the first statement in the constructor when a class contains initialized properties or has parameter properties.",
Constructors_for_derived_classes_must_contain_a_super_call: "Constructors for derived classes must contain a 'super' call.",
Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors: "Super calls are not permitted outside constructors or in nested functions inside constructors.",
_0_1_is_inaccessible: "'{0}.{1}' is inaccessible.",
this_cannot_be_referenced_in_a_module_body: "'this' cannot be referenced in a module body.",
Invalid_expression_types_not_known_to_support_the_addition_operator: "Invalid '+' expression - types not known to support the addition operator.",
The_right_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type: "The right-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.",
The_left_hand_side_of_an_arithmetic_operation_must_be_of_type_any_number_or_an_enum_type: "The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.",
An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type: "An arithmetic operand must be of type 'any', 'number' or an enum type.",
Variable_declarations_of_a_for_statement_cannot_use_a_type_annotation: "Variable declarations of a 'for' statement cannot use a type annotation.",
Variable_declarations_of_a_for_statement_must_be_of_types_string_or_any: "Variable declarations of a 'for' statement must be of types 'string' or 'any'.",
The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter: "The right-hand side of a 'for...in' statement must be of type 'any', an object type or a type parameter.",
The_left_hand_side_of_an_in_expression_must_be_of_types_any_string_or_number: "The left-hand side of an 'in' expression must be of types 'any', 'string' or 'number'.",
The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter: "The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter.",
The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter: "The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter.",
The_right_hand_side_of_an_instanceof_expression_must_be_of_type_any_or_of_a_type_assignable_to_the_Function_interface_type: "The right-hand side of an 'instanceof' expression must be of type 'any' or of a type assignable to the 'Function' interface type.",
Setters_cannot_return_a_value: "Setters cannot return a value.",
Tried_to_query_type_of_uninitialized_module_0: "Tried to query type of uninitialized module '{0}'.",
Tried_to_set_variable_type_to_uninitialized_module_type_0: "Tried to set variable type to uninitialized module type '{0}'.",
Type_0_is_not_generic: "Type '{0}' is not generic.",
Getters_must_return_a_value: "Getters must return a value.",
Getter_and_setter_accessors_do_not_agree_in_visibility: "Getter and setter accessors do not agree in visibility.",
Invalid_left_hand_side_of_assignment_expression: "Invalid left-hand side of assignment expression.",
Function_declared_a_non_void_return_type_but_has_no_return_expression: "Function declared a non-void return type, but has no return expression.",
Cannot_resolve_return_type_reference: "Cannot resolve return type reference.",
Constructors_cannot_have_a_return_type_of_void: "Constructors cannot have a return type of 'void'.",
Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2: "Subsequent variable declarations must have the same type. Variable '{0}' must be of type '{1}', but here has type '{2}'.",
All_symbols_within_a_with_block_will_be_resolved_to_any: "All symbols within a with block will be resolved to 'any'.",
Import_declarations_in_an_internal_module_cannot_reference_an_external_module: "Import declarations in an internal module cannot reference an external module.",
Class_0_declares_interface_1_but_does_not_implement_it_NL_2: "Class {0} declares interface {1} but does not implement it:{NL}{2}",
Class_0_declares_class_1_as_an_interface_but_does_not_implement_it_NL_2: "Class {0} declares class {1} as an interface but does not implement it:{NL}{2}",
The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_property_or_indexer: "The operand of an increment or decrement operator must be a variable, property or indexer.",
this_cannot_be_referenced_in_a_static_property_initializer: "'this' cannot be referenced in a static property initializer.",
Class_0_cannot_extend_class_1_NL_2: "Class '{0}' cannot extend class '{1}':{NL}{2}",
Interface_0_cannot_extend_class_1_NL_2: "Interface '{0}' cannot extend class '{1}':{NL}{2}",
Interface_0_cannot_extend_interface_1_NL_2: "Interface '{0}' cannot extend interface '{1}':{NL}{2}",
Overload_signature_is_not_compatible_with_function_definition: "Overload signature is not compatible with function definition.",
Overload_signature_is_not_compatible_with_function_definition_NL_0: "Overload signature is not compatible with function definition:{NL}{0}",
Overload_signatures_must_all_be_public_or_private: "Overload signatures must all be public or private.",
Overload_signatures_must_all_be_exported_or_not_exported: "Overload signatures must all be exported or not exported.",
Overload_signatures_must_all_be_ambient_or_non_ambient: "Overload signatures must all be ambient or non-ambient.",
Overload_signatures_must_all_be_optional_or_required: "Overload signatures must all be optional or required.",
Specialized_overload_signature_is_not_assignable_to_any_non_specialized_signature: "Specialized overload signature is not assignable to any non-specialized signature.",
this_cannot_be_referenced_in_constructor_arguments: "'this' cannot be referenced in constructor arguments.",
Instance_member_cannot_be_accessed_off_a_class: "Instance member cannot be accessed off a class.",
Untyped_function_calls_may_not_accept_type_arguments: "Untyped function calls may not accept type arguments.",
Non_generic_functions_may_not_accept_type_arguments: "Non-generic functions may not accept type arguments.",
A_generic_type_may_not_reference_itself_with_a_wrapped_form_of_its_own_type_parameters: "A generic type may not reference itself with a wrapped form of its own type parameters.",
A_rest_parameter_must_be_of_an_array_type: "A rest parameter must be of an array type.",
Overload_signature_implementation_cannot_use_specialized_type: "Overload signature implementation cannot use specialized type.",
Export_assignments_may_only_be_used_at_the_top_level_of_external_modules: "Export assignments may only be used at the top-level of external modules.",
Export_assignments_may_only_be_made_with_variables_functions_classes_interfaces_enums_and_internal_modules: "Export assignments may only be made with variables, functions, classes, interfaces, enums and internal modules.",
Only_public_methods_of_the_base_class_are_accessible_via_the_super_keyword: "Only public methods of the base class are accessible via the 'super' keyword.",
Numeric_indexer_type_0_must_be_assignable_to_string_indexer_type_1: "Numeric indexer type '{0}' must be assignable to string indexer type '{1}'.",
Numeric_indexer_type_0_must_be_assignable_to_string_indexer_type_1_NL_2: "Numeric indexer type '{0}' must be assignable to string indexer type '{1}':{NL}{2}",
All_numerically_named_properties_must_be_assignable_to_numeric_indexer_type_0: "All numerically named properties must be assignable to numeric indexer type '{0}'.",
All_numerically_named_properties_must_be_assignable_to_numeric_indexer_type_0_NL_1: "All numerically named properties must be assignable to numeric indexer type '{0}':{NL}{1}",
All_named_properties_must_be_assignable_to_string_indexer_type_0: "All named properties must be assignable to string indexer type '{0}'.",
All_named_properties_must_be_assignable_to_string_indexer_type_0_NL_1: "All named properties must be assignable to string indexer type '{0}':{NL}{1}",
A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation: "A parameter initializer is only allowed in a function or constructor implementation.",
Function_expression_declared_a_non_void_return_type_but_has_no_return_expression: "Function expression declared a non-void return type, but has no return expression.",
Import_declaration_referencing_identifier_from_internal_module_can_only_be_made_with_variables_functions_classes_interfaces_enums_and_internal_modules: "Import declaration referencing identifier from internal module can only be made with variables, functions, classes, interfaces, enums and internal modules.",
Module_0_has_no_exported_member_1: "Module '{0}' has no exported member '{1}'.",
Unable_to_resolve_module_reference_0: "Unable to resolve module reference '{0}'.",
Could_not_find_module_0_in_module_1: "Could not find module '{0}' in module '{1}'.",
Exported_import_declaration_0_is_assigned_value_with_type_that_has_or_is_using_private_type_1: "Exported import declaration '{0}' is assigned value with type that has or is using private type '{1}'.",
Exported_import_declaration_0_is_assigned_value_with_type_that_is_using_inaccessible_module_1: "Exported import declaration '{0}' is assigned value with type that is using inaccessible module '{1}'.",
Exported_import_declaration_0_is_assigned_type_that_has_or_is_using_private_type_1: "Exported import declaration '{0}' is assigned type that has or is using private type '{1}'.",
Exported_import_declaration_0_is_assigned_type_that_is_using_inaccessible_module_1: "Exported import declaration '{0}' is assigned type that is using inaccessible module '{1}'.",
Exported_import_declaration_0_is_assigned_container_that_is_or_is_using_inaccessible_module_1: "Exported import declaration '{0}' is assigned container that is or is using inaccessible module '{1}'.",
Type_name_0_in_extends_clause_does_not_reference_constructor_function_for_1: "Type name '{0}' in extends clause does not reference constructor function for '{1}'.",
Internal_module_reference_0_in_import_declaration_does_not_reference_module_instance_for_1: "Internal module reference '{0}' in import declaration does not reference module instance for '{1}'.",
Module_0_cannot_merge_with_previous_declaration_of_1_in_a_different_file_2: "Module '{0}' cannot merge with previous declaration of '{1}' in a different file '{2}'.",
Interface_0_cannot_simultaneously_extend_types_1_and_2_NL_3: "Interface '{0}' cannot simultaneously extend types '{1}' and '{2}':{NL}{3}",
Initializer_of_parameter_0_cannot_reference_identifier_1_declared_after_it: "Initializer of parameter '{0}' cannot reference identifier '{1}' declared after it.",
Ambient_external_module_declaration_cannot_be_reopened: "Ambient external module declaration cannot be reopened.",
All_declarations_of_merged_declaration_0_must_be_exported_or_not_exported: "All declarations of merged declaration '{0}' must be exported or not exported.",
super_cannot_be_referenced_in_constructor_arguments: "'super' cannot be referenced in constructor arguments.",
Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class: "Return type of constructor signature must be assignable to the instance type of the class.",
Ambient_external_module_declaration_must_be_defined_in_global_context: "Ambient external module declaration must be defined in global context.",
Ambient_external_module_declaration_cannot_specify_relative_module_name: "Ambient external module declaration cannot specify relative module name.",
Import_declaration_in_an_ambient_external_module_declaration_cannot_reference_external_module_through_relative_external_module_name: "Import declaration in an ambient external module declaration cannot reference external module through relative external module name.",
No_best_common_type_exists_among_return_expressions: "No best common type exists among return expressions.",
Import_declaration_cannot_refer_to_external_module_reference_when_noResolve_option_is_set: "Import declaration cannot refer to external module reference when --noResolve option is set.",
Duplicate_identifier_this_Compiler_uses_variable_declaration_this_to_capture_this_reference: "Duplicate identifier '_this'. Compiler uses variable declaration '_this' to capture 'this' reference.",
Duplicate_identifier_super_Compiler_uses_super_to_capture_base_class_reference: "Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.",
Expression_resolves_to_variable_declaration_this_that_compiler_uses_to_capture_this_reference: "Expression resolves to variable declaration '_this' that compiler uses to capture 'this' reference.",
Expression_resolves_to_super_that_compiler_uses_to_capture_base_class_reference: "Expression resolves to '_super' that compiler uses to capture base class reference.",
TypeParameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_type_1: "TypeParameter '{0}' of constructor signature from exported interface has or is using private type '{1}'.",
TypeParameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_type_1: "TypeParameter '{0}' of call signature from exported interface has or is using private type '{1}'.",
TypeParameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_type_1: "TypeParameter '{0}' of public static method from exported class has or is using private type '{1}'.",
TypeParameter_0_of_public_method_from_exported_class_has_or_is_using_private_type_1: "TypeParameter '{0}' of public method from exported class has or is using private type '{1}'.",
TypeParameter_0_of_method_from_exported_interface_has_or_is_using_private_type_1: "TypeParameter '{0}' of method from exported interface has or is using private type '{1}'.",
TypeParameter_0_of_exported_function_has_or_is_using_private_type_1: "TypeParameter '{0}' of exported function has or is using private type '{1}'.",
TypeParameter_0_of_constructor_signature_from_exported_interface_is_using_inaccessible_module_1: "TypeParameter '{0}' of constructor signature from exported interface is using inaccessible module {1}.",
TypeParameter_0_of_call_signature_from_exported_interface_is_using_inaccessible_module_1: "TypeParameter '{0}' of call signature from exported interface is using inaccessible module {1}",
TypeParameter_0_of_public_static_method_from_exported_class_is_using_inaccessible_module_1: "TypeParameter '{0}' of public static method from exported class is using inaccessible module {1}.",
TypeParameter_0_of_public_method_from_exported_class_is_using_inaccessible_module_1: "TypeParameter '{0}' of public method from exported class is using inaccessible module {1}.",
TypeParameter_0_of_method_from_exported_interface_is_using_inaccessible_module_1: "TypeParameter '{0}' of method from exported interface is using inaccessible module {1}.",
TypeParameter_0_of_exported_function_is_using_inaccessible_module_1: "TypeParameter '{0}' of exported function is using inaccessible module {1}.",
TypeParameter_0_of_exported_class_has_or_is_using_private_type_1: "TypeParameter '{0}' of exported class has or is using private type '{1}'.",
TypeParameter_0_of_exported_interface_has_or_is_using_private_type_1: "TypeParameter '{0}' of exported interface has or is using private type '{1}'.",
TypeParameter_0_of_exported_class_is_using_inaccessible_module_1: "TypeParameter '{0}' of exported class is using inaccessible module {1}.",
TypeParameter_0_of_exported_interface_is_using_inaccessible_module_1: "TypeParameter '{0}' of exported interface is using inaccessible module {1}.",
Duplicate_identifier_i_Compiler_uses_i_to_initialize_rest_parameter: "Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter.",
Duplicate_identifier_arguments_Compiler_uses_arguments_to_initialize_rest_parameters: "Duplicate identifier 'arguments'. Compiler uses 'arguments' to initialize rest parameters.",
No_best_common_type_exists_between_0_and_1: "No best common type exists between '{0}' and '{1}'.",
No_best_common_type_exists_between_0_1_and_2: "No best common type exists between '{0}', '{1}', and '{2}'.",
Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_an_external_module: "Duplicate identifier '{0}'. Compiler reserves name '{1}' in top level scope of an external module.",
Constraint_of_a_type_parameter_cannot_reference_any_type_parameter_from_the_same_type_parameter_list: "Constraint of a type parameter cannot reference any type parameter from the same type parameter list.",
Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor.",
Parameter_0_cannot_be_referenced_in_its_initializer: "Parameter '{0}' cannot be referenced in its initializer.",
Duplicate_string_index_signature: "Duplicate string index signature.",
Duplicate_number_index_signature: "Duplicate number index signature.",
All_declarations_of_an_interface_must_have_identical_type_parameters: "All declarations of an interface must have identical type parameters.",
Expression_resolves_to_variable_declaration_i_that_compiler_uses_to_initialize_rest_parameter: "Expression resolves to variable declaration '_i' that compiler uses to initialize rest parameter.",
Neither_type_0_nor_type_1_is_assignable_to_the_other: "Neither type '{0}' nor type '{1}' is assignable to the other.",
Neither_type_0_nor_type_1_is_assignable_to_the_other_NL_2: "Neither type '{0}' nor type '{1}' is assignable to the other:{NL}{2}",
Duplicate_function_implementation: "Duplicate function implementation.",
Function_implementation_expected: "Function implementation expected.",
Function_overload_name_must_be_0: "Function overload name must be '{0}'.",
Constructor_implementation_expected: "Constructor implementation expected.",
Class_name_cannot_be_0: "Class name cannot be '{0}'.",
Interface_name_cannot_be_0: "Interface name cannot be '{0}'.",
Enum_name_cannot_be_0: "Enum name cannot be '{0}'.",
A_module_cannot_have_multiple_export_assignments: "A module cannot have multiple export assignments.",
Export_assignment_not_allowed_in_module_with_exported_element: "Export assignment not allowed in module with exported element.",
A_parameter_property_is_only_allowed_in_a_constructor_implementation: "A parameter property is only allowed in a constructor implementation.",
Function_overload_must_be_static: "Function overload must be static.",
Function_overload_must_not_be_static: "Function overload must not be static.",
Type_0_is_missing_property_1_from_type_2: "Type '{0}' is missing property '{1}' from type '{2}'.",
Types_of_property_0_of_types_1_and_2_are_incompatible: "Types of property '{0}' of types '{1}' and '{2}' are incompatible.",
Types_of_property_0_of_types_1_and_2_are_incompatible_NL_3: "Types of property '{0}' of types '{1}' and '{2}' are incompatible:{NL}{3}",
Property_0_defined_as_private_in_type_1_is_defined_as_public_in_type_2: "Property '{0}' defined as private in type '{1}' is defined as public in type '{2}'.",
Property_0_defined_as_public_in_type_1_is_defined_as_private_in_type_2: "Property '{0}' defined as public in type '{1}' is defined as private in type '{2}'.",
Types_0_and_1_define_property_2_as_private: "Types '{0}' and '{1}' define property '{2}' as private.",
Call_signatures_of_types_0_and_1_are_incompatible: "Call signatures of types '{0}' and '{1}' are incompatible.",
Call_signatures_of_types_0_and_1_are_incompatible_NL_2: "Call signatures of types '{0}' and '{1}' are incompatible:{NL}{2}",
Type_0_requires_a_call_signature_but_type_1_lacks_one: "Type '{0}' requires a call signature, but type '{1}' lacks one.",
Construct_signatures_of_types_0_and_1_are_incompatible: "Construct signatures of types '{0}' and '{1}' are incompatible.",
Construct_signatures_of_types_0_and_1_are_incompatible_NL_2: "Construct signatures of types '{0}' and '{1}' are incompatible:{NL}{2}",
Type_0_requires_a_construct_signature_but_type_1_lacks_one: "Type '{0}' requires a construct signature, but type '{1}' lacks one.",
Index_signatures_of_types_0_and_1_are_incompatible: "Index signatures of types '{0}' and '{1}' are incompatible.",
Index_signatures_of_types_0_and_1_are_incompatible_NL_2: "Index signatures of types '{0}' and '{1}' are incompatible:{NL}{2}",
Call_signature_expects_0_or_fewer_parameters: "Call signature expects {0} or fewer parameters.",
Could_not_apply_type_0_to_argument_1_which_is_of_type_2: "Could not apply type '{0}' to argument {1} which is of type '{2}'.",
Class_0_defines_instance_member_accessor_1_but_extended_class_2_defines_it_as_instance_member_function: "Class '{0}' defines instance member accessor '{1}', but extended class '{2}' defines it as instance member function.",
Class_0_defines_instance_member_property_1_but_extended_class_2_defines_it_as_instance_member_function: "Class '{0}' defines instance member property '{1}', but extended class '{2}' defines it as instance member function.",
Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_accessor: "Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member accessor.",
Class_0_defines_instance_member_function_1_but_extended_class_2_defines_it_as_instance_member_property: "Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member property.",
Types_of_static_property_0_of_class_1_and_class_2_are_incompatible: "Types of static property '{0}' of class '{1}' and class '{2}' are incompatible.",
Types_of_static_property_0_of_class_1_and_class_2_are_incompatible_NL_3: "Types of static property '{0}' of class '{1}' and class '{2}' are incompatible:{NL}{3}",
Type_reference_cannot_refer_to_container_0: "Type reference cannot refer to container '{0}'.",
Type_reference_must_refer_to_type: "Type reference must refer to type.",
In_enums_with_multiple_declarations_only_one_declaration_can_omit_an_initializer_for_the_first_enum_element: "In enums with multiple declarations only one declaration can omit an initializer for the first enum element.",
_0_overload_s: " (+ {0} overload(s))",
Variable_declaration_cannot_have_the_same_name_as_an_import_declaration: "Variable declaration cannot have the same name as an import declaration.",
Signature_expected_0_type_arguments_got_1_instead: "Signature expected {0} type arguments, got {1} instead.",
Property_0_defined_as_optional_in_type_1_but_is_required_in_type_2: "Property '{0}' defined as optional in type '{1}', but is required in type '{2}'.",
Types_0_and_1_originating_in_infinitely_expanding_type_reference_do_not_refer_to_same_named_type: "Types '{0}' and '{1}' originating in infinitely expanding type reference do not refer to same named type.",
Types_0_and_1_originating_in_infinitely_expanding_type_reference_have_incompatible_type_arguments: "Types '{0}' and '{1}' originating in infinitely expanding type reference have incompatible type arguments.",
Types_0_and_1_originating_in_infinitely_expanding_type_reference_have_incompatible_type_arguments_NL_2: "Types '{0}' and '{1}' originating in infinitely expanding type reference have incompatible type arguments:{NL}{2}",
Named_properties_0_of_types_1_and_2_are_not_identical: "Named properties '{0}' of types '{1}' and '{2}' are not identical.",
Types_of_string_indexer_of_types_0_and_1_are_not_identical: "Types of string indexer of types '{0}' and '{1}' are not identical.",
Types_of_number_indexer_of_types_0_and_1_are_not_identical: "Types of number indexer of types '{0}' and '{1}' are not identical.",
Type_of_number_indexer_in_type_0_is_not_assignable_to_string_indexer_type_in_type_1_NL_2: "Type of number indexer in type '{0}' is not assignable to string indexer type in type '{1}'.{NL}{2}",
Type_of_property_0_in_type_1_is_not_assignable_to_string_indexer_type_in_type_2_NL_3: "Type of property '{0}' in type '{1}' is not assignable to string indexer type in type '{2}'.{NL}{3}",
Type_of_property_0_in_type_1_is_not_assignable_to_number_indexer_type_in_type_2_NL_3: "Type of property '{0}' in type '{1}' is not assignable to number indexer type in type '{2}'.{NL}{3}",
Static_property_0_defined_as_private_in_type_1_is_defined_as_public_in_type_2: "Static property '{0}' defined as private in type '{1}' is defined as public in type '{2}'.",
Static_property_0_defined_as_public_in_type_1_is_defined_as_private_in_type_2: "Static property '{0}' defined as public in type '{1}' is defined as private in type '{2}'.",
Types_0_and_1_define_static_property_2_as_private: "Types '{0}' and '{1}' define static property '{2}' as private.",
Current_host_does_not_support_0_option: "Current host does not support '{0}' option.",
ECMAScript_target_version_0_not_supported_Specify_a_valid_target_version_1_default_or_2: "ECMAScript target version '{0}' not supported. Specify a valid target version: '{1}' (default), or '{2}'",
Argument_for_0_option_must_be_1_or_2: "Argument for '{0}' option must be '{1}' or '{2}'",
Could_not_find_file_0: "Could not find file: '{0}'.",
A_file_cannot_have_a_reference_to_itself: "A file cannot have a reference to itself.",
Cannot_resolve_referenced_file_0: "Cannot resolve referenced file: '{0}'.",
Cannot_find_the_common_subdirectory_path_for_the_input_files: "Cannot find the common subdirectory path for the input files.",
Emit_Error_0: "Emit Error: {0}.",
Cannot_read_file_0_1: "Cannot read file '{0}': {1}",
Unsupported_file_encoding: "Unsupported file encoding.",
Locale_must_be_of_the_form_language_or_language_territory_For_example_0_or_1: "Locale must be of the form <language> or <language>-<territory>. For example '{0}' or '{1}'.",
Unsupported_locale_0: "Unsupported locale: '{0}'.",
Execution_Failed_NL: "Execution Failed.{NL}",
Invalid_call_to_up: "Invalid call to 'up'",
Invalid_call_to_down: "Invalid call to 'down'",
Base64_value_0_finished_with_a_continuation_bit: "Base64 value '{0}' finished with a continuation bit.",
Unknown_compiler_option_0: "Unknown compiler option '{0}'",
Expected_0_arguments_to_message_got_1_instead: "Expected {0} arguments to message, got {1} instead.",
Expected_the_message_0_to_have_1_arguments_but_it_had_2: "Expected the message '{0}' to have {1} arguments, but it had {2}",
Could_not_delete_file_0: "Could not delete file '{0}'",
Could_not_create_directory_0: "Could not create directory '{0}'",
Error_while_executing_file_0: "Error while executing file '{0}': ",
Cannot_compile_external_modules_unless_the_module_flag_is_provided: "Cannot compile external modules unless the '--module' flag is provided.",
Option_mapRoot_cannot_be_specified_without_specifying_sourcemap_option: "Option mapRoot cannot be specified without specifying sourcemap option.",
Option_sourceRoot_cannot_be_specified_without_specifying_sourcemap_option: "Option sourceRoot cannot be specified without specifying sourcemap option.",
Options_mapRoot_and_sourceRoot_cannot_be_specified_without_specifying_sourcemap_option: "Options mapRoot and sourceRoot cannot be specified without specifying sourcemap option.",
Option_0_specified_without_1: "Option '{0}' specified without '{1}'",
codepage_option_not_supported_on_current_platform: "'codepage' option not supported on current platform.",
Concatenate_and_emit_output_to_single_file: "Concatenate and emit output to single file.",
Generates_corresponding_0_file: "Generates corresponding {0} file.",
Specifies_the_location_where_debugger_should_locate_map_files_instead_of_generated_locations: "Specifies the location where debugger should locate map files instead of generated locations.",
Specifies_the_location_where_debugger_should_locate_TypeScript_files_instead_of_source_locations: "Specifies the location where debugger should locate TypeScript files instead of source locations.",
Watch_input_files: "Watch input files.",
Redirect_output_structure_to_the_directory: "Redirect output structure to the directory.",
Do_not_emit_comments_to_output: "Do not emit comments to output.",
Skip_resolution_and_preprocessing: "Skip resolution and preprocessing.",
Specify_ECMAScript_target_version_0_default_or_1: "Specify ECMAScript target version: '{0}' (default), or '{1}'",
Specify_module_code_generation_0_or_1: "Specify module code generation: '{0}' or '{1}'",
Print_this_message: "Print this message.",
Print_the_compiler_s_version_0: "Print the compiler's version: {0}",
Allow_use_of_deprecated_0_keyword_when_referencing_an_external_module: "Allow use of deprecated '{0}' keyword when referencing an external module.",
Specify_locale_for_errors_and_messages_For_example_0_or_1: "Specify locale for errors and messages. For example '{0}' or '{1}'",
Syntax_0: "Syntax: {0}",
options: "options",
file1: "file",
Examples: "Examples:",
Options: "Options:",
Insert_command_line_options_and_files_from_a_file: "Insert command line options and files from a file.",
Version_0: "Version {0}",
Use_the_0_flag_to_see_options: "Use the '{0}' flag to see options.",
NL_Recompiling_0: "{NL}Recompiling ({0}):",
STRING: "STRING",
KIND: "KIND",
file2: "FILE",
VERSION: "VERSION",
LOCATION: "LOCATION",
DIRECTORY: "DIRECTORY",
NUMBER: "NUMBER",
Specify_the_codepage_to_use_when_opening_source_files: "Specify the codepage to use when opening source files.",
Additional_locations: "Additional locations:",
This_version_of_the_Javascript_runtime_does_not_support_the_0_function: "This version of the Javascript runtime does not support the '{0}' function.",
Unknown_rule: "Unknown rule.",
Invalid_line_number_0: "Invalid line number ({0})",
Warn_on_expressions_and_declarations_with_an_implied_any_type: "Warn on expressions and declarations with an implied 'any' type.",
Variable_0_implicitly_has_an_any_type: "Variable '{0}' implicitly has an 'any' type.",
Parameter_0_of_1_implicitly_has_an_any_type: "Parameter '{0}' of '{1}' implicitly has an 'any' type.",
Parameter_0_of_function_type_implicitly_has_an_any_type: "Parameter '{0}' of function type implicitly has an 'any' type.",
Member_0_of_object_type_implicitly_has_an_any_type: "Member '{0}' of object type implicitly has an 'any' type.",
new_expression_which_lacks_a_constructor_signature_implicitly_has_an_any_type: "'new' expression, which lacks a constructor signature, implicitly has an 'any' type.",
_0_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: "'{0}', which lacks return-type annotation, implicitly has an 'any' return type.",
Function_expression_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: "Function expression, which lacks return-type annotation, implicitly has an 'any' return type.",
Parameter_0_of_lambda_function_implicitly_has_an_any_type: "Parameter '{0}' of lambda function implicitly has an 'any' type.",
Constructor_signature_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: "Constructor signature, which lacks return-type annotation, implicitly has an 'any' return type.",
Lambda_Function_which_lacks_return_type_annotation_implicitly_has_an_any_return_type: "Lambda Function, which lacks return-type annotation, implicitly has an 'any' return type.",
Array_Literal_implicitly_has_an_any_type_from_widening: "Array Literal implicitly has an 'any' type from widening.",
_0_which_lacks_get_accessor_and_parameter_type_annotation_on_set_accessor_implicitly_has_an_any_type: "'{0}', which lacks 'get' accessor and parameter type annotation on 'set' accessor, implicitly has an 'any' type.",
Index_signature_of_object_type_implicitly_has_an_any_type: "Index signature of object type implicitly has an 'any' type.",
Object_literal_s_property_0_implicitly_has_an_any_type_from_widening: "Object literal's property '{0}' implicitly has an 'any' type from widening.",
};
}
@@ -0,0 +1,446 @@
// <auto-generated />
/// <reference path="..\core\diagnosticCategory.ts" />
module TypeScript {
export var diagnosticInformationMap: ts.Map<any> = {
"error TS{0}: {1}": { "code": 0, "category": DiagnosticCategory.NoPrefix },
"warning TS{0}: {1}": { "code": 1, "category": DiagnosticCategory.NoPrefix },
"Unrecognized escape sequence.": { "code": 1000, "category": DiagnosticCategory.Error },
"Unexpected character {0}.": { "code": 1001, "category": DiagnosticCategory.Error },
"Missing close quote character.": { "code": 1002, "category": DiagnosticCategory.Error },
"Identifier expected.": { "code": 1003, "category": DiagnosticCategory.Error },
"'{0}' keyword expected.": { "code": 1004, "category": DiagnosticCategory.Error },
"'{0}' expected.": { "code": 1005, "category": DiagnosticCategory.Error },
"Identifier expected; '{0}' is a keyword.": { "code": 1006, "category": DiagnosticCategory.Error },
"Automatic semicolon insertion not allowed.": { "code": 1007, "category": DiagnosticCategory.Error },
"Unexpected token; '{0}' expected.": { "code": 1008, "category": DiagnosticCategory.Error },
"Trailing comma not allowed.": { "code": 1009, "category": DiagnosticCategory.Error },
"'*/' expected.": { "code": 1010, "category": DiagnosticCategory.Error },
"'public' or 'private' modifier must precede 'static'.": { "code": 1011, "category": DiagnosticCategory.Error },
"Unexpected token.": { "code": 1012, "category": DiagnosticCategory.Error },
"Catch clause parameter cannot have a type annotation.": { "code": 1013, "category": DiagnosticCategory.Error },
"A rest parameter must be last in a parameter list.": { "code": 1014, "category": DiagnosticCategory.Error },
"Parameter cannot have question mark and initializer.": { "code": 1015, "category": DiagnosticCategory.Error },
"A required parameter cannot follow an optional parameter.": { "code": 1016, "category": DiagnosticCategory.Error },
"Index signatures cannot have rest parameters.": { "code": 1017, "category": DiagnosticCategory.Error },
"Index signature parameter cannot have accessibility modifiers.": { "code": 1018, "category": DiagnosticCategory.Error },
"Index signature parameter cannot have a question mark.": { "code": 1019, "category": DiagnosticCategory.Error },
"Index signature parameter cannot have an initializer.": { "code": 1020, "category": DiagnosticCategory.Error },
"Index signature must have a type annotation.": { "code": 1021, "category": DiagnosticCategory.Error },
"Index signature parameter must have a type annotation.": { "code": 1022, "category": DiagnosticCategory.Error },
"Index signature parameter type must be 'string' or 'number'.": { "code": 1023, "category": DiagnosticCategory.Error },
"'extends' clause already seen.": { "code": 1024, "category": DiagnosticCategory.Error },
"'extends' clause must precede 'implements' clause.": { "code": 1025, "category": DiagnosticCategory.Error },
"Classes can only extend a single class.": { "code": 1026, "category": DiagnosticCategory.Error },
"'implements' clause already seen.": { "code": 1027, "category": DiagnosticCategory.Error },
"Accessibility modifier already seen.": { "code": 1028, "category": DiagnosticCategory.Error },
"'{0}' modifier must precede '{1}' modifier.": { "code": 1029, "category": DiagnosticCategory.Error },
"'{0}' modifier already seen.": { "code": 1030, "category": DiagnosticCategory.Error },
"'{0}' modifier cannot appear on a class element.": { "code": 1031, "category": DiagnosticCategory.Error },
"Interface declaration cannot have 'implements' clause.": { "code": 1032, "category": DiagnosticCategory.Error },
"'super' invocation cannot have type arguments.": { "code": 1034, "category": DiagnosticCategory.Error },
"Only ambient modules can use quoted names.": { "code": 1035, "category": DiagnosticCategory.Error },
"Statements are not allowed in ambient contexts.": { "code": 1036, "category": DiagnosticCategory.Error },
"A function implementation cannot be declared in an ambient context.": { "code": 1037, "category": DiagnosticCategory.Error },
"A 'declare' modifier cannot be used in an already ambient context.": { "code": 1038, "category": DiagnosticCategory.Error },
"Initializers are not allowed in ambient contexts.": { "code": 1039, "category": DiagnosticCategory.Error },
"'{0}' modifier cannot appear on a module element.": { "code": 1044, "category": DiagnosticCategory.Error },
"A 'declare' modifier cannot be used with an interface declaration.": { "code": 1045, "category": DiagnosticCategory.Error },
"A 'declare' modifier is required for a top level declaration in a .d.ts file.": { "code": 1046, "category": DiagnosticCategory.Error },
"A rest parameter cannot be optional.": { "code": 1047, "category": DiagnosticCategory.Error },
"A rest parameter cannot have an initializer.": { "code": 1048, "category": DiagnosticCategory.Error },
"'set' accessor must have exactly one parameter.": { "code": 1049, "category": DiagnosticCategory.Error },
"'set' accessor parameter cannot be optional.": { "code": 1051, "category": DiagnosticCategory.Error },
"'set' accessor parameter cannot have an initializer.": { "code": 1052, "category": DiagnosticCategory.Error },
"'set' accessor cannot have rest parameter.": { "code": 1053, "category": DiagnosticCategory.Error },
"'get' accessor cannot have parameters.": { "code": 1054, "category": DiagnosticCategory.Error },
"Modifiers cannot appear here.": { "code": 1055, "category": DiagnosticCategory.Error },
"Accessors are only available when targeting ECMAScript 5 and higher.": { "code": 1056, "category": DiagnosticCategory.Error },
"Enum member must have initializer.": { "code": 1061, "category": DiagnosticCategory.Error },
"Export assignment cannot be used in internal modules.": { "code": 1063, "category": DiagnosticCategory.Error },
"Ambient enum elements can only have integer literal initializers.": { "code": 1066, "category": DiagnosticCategory.Error },
"module, class, interface, enum, import or statement": { "code": 1067, "category": DiagnosticCategory.NoPrefix },
"constructor, function, accessor or variable": { "code": 1068, "category": DiagnosticCategory.NoPrefix },
"statement": { "code": 1069, "category": DiagnosticCategory.NoPrefix },
"case or default clause": { "code": 1070, "category": DiagnosticCategory.NoPrefix },
"identifier": { "code": 1071, "category": DiagnosticCategory.NoPrefix },
"call, construct, index, property or function signature": { "code": 1072, "category": DiagnosticCategory.NoPrefix },
"expression": { "code": 1073, "category": DiagnosticCategory.NoPrefix },
"type name": { "code": 1074, "category": DiagnosticCategory.NoPrefix },
"property or accessor": { "code": 1075, "category": DiagnosticCategory.NoPrefix },
"parameter": { "code": 1076, "category": DiagnosticCategory.NoPrefix },
"type": { "code": 1077, "category": DiagnosticCategory.NoPrefix },
"type parameter": { "code": 1078, "category": DiagnosticCategory.NoPrefix },
"A 'declare' modifier cannot be used with an import declaration.": { "code": 1079, "category": DiagnosticCategory.Error },
"Invalid 'reference' directive syntax.": { "code": 1084, "category": DiagnosticCategory.Error },
"Octal literals are not available when targeting ECMAScript 5 and higher.": { "code": 1085, "category": DiagnosticCategory.Error },
"Accessors are not allowed in ambient contexts.": { "code": 1086, "category": DiagnosticCategory.Error },
"'{0}' modifier cannot appear on a constructor declaration.": { "code": 1089, "category": DiagnosticCategory.Error },
"'{0}' modifier cannot appear on a parameter.": { "code": 1090, "category": DiagnosticCategory.Error },
"Only a single variable declaration is allowed in a 'for...in' statement.": { "code": 1091, "category": DiagnosticCategory.Error },
"Type parameters cannot appear on a constructor declaration.": { "code": 1092, "category": DiagnosticCategory.Error },
"Type annotation cannot appear on a constructor declaration.": { "code": 1093, "category": DiagnosticCategory.Error },
"Type parameters cannot appear on an accessor.": { "code": 1094, "category": DiagnosticCategory.Error },
"Type annotation cannot appear on a 'set' accessor.": { "code": 1095, "category": DiagnosticCategory.Error },
"Index signature must have exactly one parameter.": { "code": 1096, "category": DiagnosticCategory.Error },
"'{0}' list cannot be empty.": { "code": 1097, "category": DiagnosticCategory.Error },
"variable declaration": { "code": 1098, "category": DiagnosticCategory.NoPrefix },
"type argument": { "code": 1099, "category": DiagnosticCategory.NoPrefix },
"Invalid use of '{0}' in strict mode.": { "code": 1100, "category": DiagnosticCategory.Error },
"'with' statements are not allowed in strict mode.": { "code": 1101, "category": DiagnosticCategory.Error },
"'delete' cannot be called on an identifier in strict mode.": { "code": 1102, "category": DiagnosticCategory.Error },
"Invalid left-hand side in 'for...in' statement.": { "code": 1103, "category": DiagnosticCategory.Error },
"'continue' statement can only be used within an enclosing iteration statement.": { "code": 1104, "category": DiagnosticCategory.Error },
"'break' statement can only be used within an enclosing iteration or switch statement.": { "code": 1105, "category": DiagnosticCategory.Error },
"Jump target not found.": { "code": 1106, "category": DiagnosticCategory.Error },
"Jump target cannot cross function boundary.": { "code": 1107, "category": DiagnosticCategory.Error },
"'return' statement must be contained within a function body.": { "code": 1108, "category": DiagnosticCategory.Error },
"Expression expected.": { "code": 1109, "category": DiagnosticCategory.Error },
"Type expected.": { "code": 1110, "category": DiagnosticCategory.Error },
"Duplicate identifier '{0}'.": { "code": 2000, "category": DiagnosticCategory.Error },
"The name '{0}' does not exist in the current scope.": { "code": 2001, "category": DiagnosticCategory.Error },
"The name '{0}' does not refer to a value.": { "code": 2002, "category": DiagnosticCategory.Error },
"'super' can only be used inside a class instance method.": { "code": 2003, "category": DiagnosticCategory.Error },
"The left-hand side of an assignment expression must be a variable, property or indexer.": { "code": 2004, "category": DiagnosticCategory.Error },
"Value of type '{0}' is not callable. Did you mean to include 'new'?": { "code": 2161, "category": DiagnosticCategory.Error },
"Value of type '{0}' is not callable.": { "code": 2006, "category": DiagnosticCategory.Error },
"Value of type '{0}' is not newable.": { "code": 2007, "category": DiagnosticCategory.Error },
"An index expression argument must be 'string', 'number', or 'any'.": { "code": 2008, "category": DiagnosticCategory.Error },
"Operator '{0}' cannot be applied to types '{1}' and '{2}'.": { "code": 2009, "category": DiagnosticCategory.Error },
"Type '{0}' is not assignable to type '{1}'.": { "code": 2011, "category": DiagnosticCategory.Error },
"Type '{0}' is not assignable to type '{1}':{NL}{2}": { "code": 2012, "category": DiagnosticCategory.Error },
"Expected var, class, interface, or module.": { "code": 2013, "category": DiagnosticCategory.Error },
"Getter '{0}' already declared.": { "code": 2015, "category": DiagnosticCategory.Error },
"Setter '{0}' already declared.": { "code": 2016, "category": DiagnosticCategory.Error },
"Exported class '{0}' extends private class '{1}'.": { "code": 2018, "category": DiagnosticCategory.Error },
"Exported class '{0}' implements private interface '{1}'.": { "code": 2019, "category": DiagnosticCategory.Error },
"Exported interface '{0}' extends private interface '{1}'.": { "code": 2020, "category": DiagnosticCategory.Error },
"Exported class '{0}' extends class from inaccessible module {1}.": { "code": 2021, "category": DiagnosticCategory.Error },
"Exported class '{0}' implements interface from inaccessible module {1}.": { "code": 2022, "category": DiagnosticCategory.Error },
"Exported interface '{0}' extends interface from inaccessible module {1}.": { "code": 2023, "category": DiagnosticCategory.Error },
"Public static property '{0}' of exported class has or is using private type '{1}'.": { "code": 2024, "category": DiagnosticCategory.Error },
"Public property '{0}' of exported class has or is using private type '{1}'.": { "code": 2025, "category": DiagnosticCategory.Error },
"Property '{0}' of exported interface has or is using private type '{1}'.": { "code": 2026, "category": DiagnosticCategory.Error },
"Exported variable '{0}' has or is using private type '{1}'.": { "code": 2027, "category": DiagnosticCategory.Error },
"Public static property '{0}' of exported class is using inaccessible module {1}.": { "code": 2028, "category": DiagnosticCategory.Error },
"Public property '{0}' of exported class is using inaccessible module {1}.": { "code": 2029, "category": DiagnosticCategory.Error },
"Property '{0}' of exported interface is using inaccessible module {1}.": { "code": 2030, "category": DiagnosticCategory.Error },
"Exported variable '{0}' is using inaccessible module {1}.": { "code": 2031, "category": DiagnosticCategory.Error },
"Parameter '{0}' of constructor from exported class has or is using private type '{1}'.": { "code": 2032, "category": DiagnosticCategory.Error },
"Parameter '{0}' of public static property setter from exported class has or is using private type '{1}'.": { "code": 2033, "category": DiagnosticCategory.Error },
"Parameter '{0}' of public property setter from exported class has or is using private type '{1}'.": { "code": 2034, "category": DiagnosticCategory.Error },
"Parameter '{0}' of constructor signature from exported interface has or is using private type '{1}'.": { "code": 2035, "category": DiagnosticCategory.Error },
"Parameter '{0}' of call signature from exported interface has or is using private type '{1}'.": { "code": 2036, "category": DiagnosticCategory.Error },
"Parameter '{0}' of public static method from exported class has or is using private type '{1}'.": { "code": 2037, "category": DiagnosticCategory.Error },
"Parameter '{0}' of public method from exported class has or is using private type '{1}'.": { "code": 2038, "category": DiagnosticCategory.Error },
"Parameter '{0}' of method from exported interface has or is using private type '{1}'.": { "code": 2039, "category": DiagnosticCategory.Error },
"Parameter '{0}' of exported function has or is using private type '{1}'.": { "code": 2040, "category": DiagnosticCategory.Error },
"Parameter '{0}' of constructor from exported class is using inaccessible module {1}.": { "code": 2041, "category": DiagnosticCategory.Error },
"Parameter '{0}' of public static property setter from exported class is using inaccessible module {1}.": { "code": 2042, "category": DiagnosticCategory.Error },
"Parameter '{0}' of public property setter from exported class is using inaccessible module {1}.": { "code": 2043, "category": DiagnosticCategory.Error },
"Parameter '{0}' of constructor signature from exported interface is using inaccessible module {1}.": { "code": 2044, "category": DiagnosticCategory.Error },
"Parameter '{0}' of call signature from exported interface is using inaccessible module {1}": { "code": 2045, "category": DiagnosticCategory.Error },
"Parameter '{0}' of public static method from exported class is using inaccessible module {1}.": { "code": 2046, "category": DiagnosticCategory.Error },
"Parameter '{0}' of public method from exported class is using inaccessible module {1}.": { "code": 2047, "category": DiagnosticCategory.Error },
"Parameter '{0}' of method from exported interface is using inaccessible module {1}.": { "code": 2048, "category": DiagnosticCategory.Error },
"Parameter '{0}' of exported function is using inaccessible module {1}.": { "code": 2049, "category": DiagnosticCategory.Error },
"Return type of public static property getter from exported class has or is using private type '{0}'.": { "code": 2050, "category": DiagnosticCategory.Error },
"Return type of public property getter from exported class has or is using private type '{0}'.": { "code": 2051, "category": DiagnosticCategory.Error },
"Return type of constructor signature from exported interface has or is using private type '{0}'.": { "code": 2052, "category": DiagnosticCategory.Error },
"Return type of call signature from exported interface has or is using private type '{0}'.": { "code": 2053, "category": DiagnosticCategory.Error },
"Return type of index signature from exported interface has or is using private type '{0}'.": { "code": 2054, "category": DiagnosticCategory.Error },
"Return type of public static method from exported class has or is using private type '{0}'.": { "code": 2055, "category": DiagnosticCategory.Error },
"Return type of public method from exported class has or is using private type '{0}'.": { "code": 2056, "category": DiagnosticCategory.Error },
"Return type of method from exported interface has or is using private type '{0}'.": { "code": 2057, "category": DiagnosticCategory.Error },
"Return type of exported function has or is using private type '{0}'.": { "code": 2058, "category": DiagnosticCategory.Error },
"Return type of public static property getter from exported class is using inaccessible module {0}.": { "code": 2059, "category": DiagnosticCategory.Error },
"Return type of public property getter from exported class is using inaccessible module {0}.": { "code": 2060, "category": DiagnosticCategory.Error },
"Return type of constructor signature from exported interface is using inaccessible module {0}.": { "code": 2061, "category": DiagnosticCategory.Error },
"Return type of call signature from exported interface is using inaccessible module {0}.": { "code": 2062, "category": DiagnosticCategory.Error },
"Return type of index signature from exported interface is using inaccessible module {0}.": { "code": 2063, "category": DiagnosticCategory.Error },
"Return type of public static method from exported class is using inaccessible module {0}.": { "code": 2064, "category": DiagnosticCategory.Error },
"Return type of public method from exported class is using inaccessible module {0}.": { "code": 2065, "category": DiagnosticCategory.Error },
"Return type of method from exported interface is using inaccessible module {0}.": { "code": 2066, "category": DiagnosticCategory.Error },
"Return type of exported function is using inaccessible module {0}.": { "code": 2067, "category": DiagnosticCategory.Error },
"'new T[]' cannot be used to create an array. Use 'new Array<T>()' instead.": { "code": 2068, "category": DiagnosticCategory.Error },
"A parameter list must follow a generic type argument list. '(' expected.": { "code": 2069, "category": DiagnosticCategory.Error },
"Multiple constructor implementations are not allowed.": { "code": 2070, "category": DiagnosticCategory.Error },
"Cannot find external module '{0}'.": { "code": 2071, "category": DiagnosticCategory.Error },
"Module cannot be aliased to a non-module type.": { "code": 2072, "category": DiagnosticCategory.Error },
"A class may only extend another class.": { "code": 2073, "category": DiagnosticCategory.Error },
"A class may only implement another class or interface.": { "code": 2074, "category": DiagnosticCategory.Error },
"An interface may only extend a class or another interface.": { "code": 2075, "category": DiagnosticCategory.Error },
"Unable to resolve type.": { "code": 2077, "category": DiagnosticCategory.Error },
"Unable to resolve type of '{0}'.": { "code": 2078, "category": DiagnosticCategory.Error },
"Unable to resolve type parameter constraint.": { "code": 2079, "category": DiagnosticCategory.Error },
"Type parameter constraint cannot be a primitive type.": { "code": 2080, "category": DiagnosticCategory.Error },
"Supplied parameters do not match any signature of call target.": { "code": 2081, "category": DiagnosticCategory.Error },
"Supplied parameters do not match any signature of call target:{NL}{0}": { "code": 2082, "category": DiagnosticCategory.Error },
"Cannot use 'new' with an expression whose type lacks a signature.": { "code": 2083, "category": DiagnosticCategory.Error },
"Only a void function can be called with the 'new' keyword.": { "code": 2084, "category": DiagnosticCategory.Error },
"Could not select overload for 'new' expression.": { "code": 2085, "category": DiagnosticCategory.Error },
"Type '{0}' does not satisfy the constraint '{1}'.": { "code": 2086, "category": DiagnosticCategory.Error },
"Could not select overload for 'call' expression.": { "code": 2087, "category": DiagnosticCategory.Error },
"Cannot invoke an expression whose type lacks a call signature.": { "code": 2088, "category": DiagnosticCategory.Error },
"Calls to 'super' are only valid inside a class.": { "code": 2089, "category": DiagnosticCategory.Error },
"Generic type '{0}' requires {1} type argument(s).": { "code": 2090, "category": DiagnosticCategory.Error },
"Type of array literal cannot be determined. Best common type could not be found for array elements.": { "code": 2092, "category": DiagnosticCategory.Error },
"Could not find enclosing symbol for dotted name '{0}'.": { "code": 2093, "category": DiagnosticCategory.Error },
"Property '{0}' does not exist on value of type '{1}'.": { "code": 2094, "category": DiagnosticCategory.Error },
"Cannot find name '{0}'.": { "code": 2095, "category": DiagnosticCategory.Error },
"'get' and 'set' accessor must have the same type.": { "code": 2096, "category": DiagnosticCategory.Error },
"'this' cannot be referenced in current location.": { "code": 2097, "category": DiagnosticCategory.Error },
"Static members cannot reference class type parameters.": { "code": 2099, "category": DiagnosticCategory.Error },
"Type '{0}' recursively references itself as a base type.": { "code": 2100, "category": DiagnosticCategory.Error },
"'super' property access is permitted only in a constructor, member function, or member accessor of a derived class.": { "code": 2102, "category": DiagnosticCategory.Error },
"'super' can only be referenced in a derived class.": { "code": 2103, "category": DiagnosticCategory.Error },
"A 'super' call must be the first statement in the constructor when a class contains initialized properties or has parameter properties.": { "code": 2104, "category": DiagnosticCategory.Error },
"Constructors for derived classes must contain a 'super' call.": { "code": 2105, "category": DiagnosticCategory.Error },
"Super calls are not permitted outside constructors or in nested functions inside constructors.": { "code": 2106, "category": DiagnosticCategory.Error },
"'{0}.{1}' is inaccessible.": { "code": 2107, "category": DiagnosticCategory.Error },
"'this' cannot be referenced in a module body.": { "code": 2108, "category": DiagnosticCategory.Error },
"Invalid '+' expression - types not known to support the addition operator.": { "code": 2111, "category": DiagnosticCategory.Error },
"The right-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.": { "code": 2112, "category": DiagnosticCategory.Error },
"The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type.": { "code": 2113, "category": DiagnosticCategory.Error },
"An arithmetic operand must be of type 'any', 'number' or an enum type.": { "code": 2114, "category": DiagnosticCategory.Error },
"Variable declarations of a 'for' statement cannot use a type annotation.": { "code": 2115, "category": DiagnosticCategory.Error },
"Variable declarations of a 'for' statement must be of types 'string' or 'any'.": { "code": 2116, "category": DiagnosticCategory.Error },
"The right-hand side of a 'for...in' statement must be of type 'any', an object type or a type parameter.": { "code": 2117, "category": DiagnosticCategory.Error },
"The left-hand side of an 'in' expression must be of types 'any', 'string' or 'number'.": { "code": 2118, "category": DiagnosticCategory.Error },
"The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter.": { "code": 2119, "category": DiagnosticCategory.Error },
"The left-hand side of an 'instanceof' expression must be of type 'any', an object type or a type parameter.": { "code": 2120, "category": DiagnosticCategory.Error },
"The right-hand side of an 'instanceof' expression must be of type 'any' or of a type assignable to the 'Function' interface type.": { "code": 2121, "category": DiagnosticCategory.Error },
"Setters cannot return a value.": { "code": 2122, "category": DiagnosticCategory.Error },
"Tried to query type of uninitialized module '{0}'.": { "code": 2123, "category": DiagnosticCategory.Error },
"Tried to set variable type to uninitialized module type '{0}'.": { "code": 2124, "category": DiagnosticCategory.Error },
"Type '{0}' is not generic.": { "code": 2125, "category": DiagnosticCategory.Error },
"Getters must return a value.": { "code": 2126, "category": DiagnosticCategory.Error },
"Getter and setter accessors do not agree in visibility.": { "code": 2127, "category": DiagnosticCategory.Error },
"Invalid left-hand side of assignment expression.": { "code": 2130, "category": DiagnosticCategory.Error },
"Function declared a non-void return type, but has no return expression.": { "code": 2131, "category": DiagnosticCategory.Error },
"Cannot resolve return type reference.": { "code": 2132, "category": DiagnosticCategory.Error },
"Constructors cannot have a return type of 'void'.": { "code": 2133, "category": DiagnosticCategory.Error },
"Subsequent variable declarations must have the same type. Variable '{0}' must be of type '{1}', but here has type '{2}'.": { "code": 2134, "category": DiagnosticCategory.Error },
"All symbols within a with block will be resolved to 'any'.": { "code": 2135, "category": DiagnosticCategory.Error },
"Import declarations in an internal module cannot reference an external module.": { "code": 2136, "category": DiagnosticCategory.Error },
"Class {0} declares interface {1} but does not implement it:{NL}{2}": { "code": 2137, "category": DiagnosticCategory.Error },
"Class {0} declares class {1} as an interface but does not implement it:{NL}{2}": { "code": 2138, "category": DiagnosticCategory.Error },
"The operand of an increment or decrement operator must be a variable, property or indexer.": { "code": 2139, "category": DiagnosticCategory.Error },
"'this' cannot be referenced in a static property initializer.": { "code": 2140, "category": DiagnosticCategory.Error },
"Class '{0}' cannot extend class '{1}':{NL}{2}": { "code": 2141, "category": DiagnosticCategory.Error },
"Interface '{0}' cannot extend class '{1}':{NL}{2}": { "code": 2142, "category": DiagnosticCategory.Error },
"Interface '{0}' cannot extend interface '{1}':{NL}{2}": { "code": 2143, "category": DiagnosticCategory.Error },
"Overload signature is not compatible with function definition.": { "code": 2148, "category": DiagnosticCategory.Error },
"Overload signature is not compatible with function definition:{NL}{0}": { "code": 2149, "category": DiagnosticCategory.Error },
"Overload signatures must all be public or private.": { "code": 2150, "category": DiagnosticCategory.Error },
"Overload signatures must all be exported or not exported.": { "code": 2151, "category": DiagnosticCategory.Error },
"Overload signatures must all be ambient or non-ambient.": { "code": 2152, "category": DiagnosticCategory.Error },
"Overload signatures must all be optional or required.": { "code": 2153, "category": DiagnosticCategory.Error },
"Specialized overload signature is not assignable to any non-specialized signature.": { "code": 2154, "category": DiagnosticCategory.Error },
"'this' cannot be referenced in constructor arguments.": { "code": 2155, "category": DiagnosticCategory.Error },
"Instance member cannot be accessed off a class.": { "code": 2157, "category": DiagnosticCategory.Error },
"Untyped function calls may not accept type arguments.": { "code": 2158, "category": DiagnosticCategory.Error },
"Non-generic functions may not accept type arguments.": { "code": 2159, "category": DiagnosticCategory.Error },
"A generic type may not reference itself with a wrapped form of its own type parameters.": { "code": 2160, "category": DiagnosticCategory.Error },
"A rest parameter must be of an array type.": { "code": 2162, "category": DiagnosticCategory.Error },
"Overload signature implementation cannot use specialized type.": { "code": 2163, "category": DiagnosticCategory.Error },
"Export assignments may only be used at the top-level of external modules.": { "code": 2164, "category": DiagnosticCategory.Error },
"Export assignments may only be made with variables, functions, classes, interfaces, enums and internal modules.": { "code": 2165, "category": DiagnosticCategory.Error },
"Only public methods of the base class are accessible via the 'super' keyword.": { "code": 2166, "category": DiagnosticCategory.Error },
"Numeric indexer type '{0}' must be assignable to string indexer type '{1}'.": { "code": 2167, "category": DiagnosticCategory.Error },
"Numeric indexer type '{0}' must be assignable to string indexer type '{1}':{NL}{2}": { "code": 2168, "category": DiagnosticCategory.Error },
"All numerically named properties must be assignable to numeric indexer type '{0}'.": { "code": 2169, "category": DiagnosticCategory.Error },
"All numerically named properties must be assignable to numeric indexer type '{0}':{NL}{1}": { "code": 2170, "category": DiagnosticCategory.Error },
"All named properties must be assignable to string indexer type '{0}'.": { "code": 2171, "category": DiagnosticCategory.Error },
"All named properties must be assignable to string indexer type '{0}':{NL}{1}": { "code": 2172, "category": DiagnosticCategory.Error },
"A parameter initializer is only allowed in a function or constructor implementation.": { "code": 2174, "category": DiagnosticCategory.Error },
"Function expression declared a non-void return type, but has no return expression.": { "code": 2176, "category": DiagnosticCategory.Error },
"Import declaration referencing identifier from internal module can only be made with variables, functions, classes, interfaces, enums and internal modules.": { "code": 2177, "category": DiagnosticCategory.Error },
"Module '{0}' has no exported member '{1}'.": { "code": 2178, "category": DiagnosticCategory.Error },
"Unable to resolve module reference '{0}'.": { "code": 2179, "category": DiagnosticCategory.Error },
"Could not find module '{0}' in module '{1}'.": { "code": 2180, "category": DiagnosticCategory.Error },
"Exported import declaration '{0}' is assigned value with type that has or is using private type '{1}'.": { "code": 2181, "category": DiagnosticCategory.Error },
"Exported import declaration '{0}' is assigned value with type that is using inaccessible module '{1}'.": { "code": 2182, "category": DiagnosticCategory.Error },
"Exported import declaration '{0}' is assigned type that has or is using private type '{1}'.": { "code": 2183, "category": DiagnosticCategory.Error },
"Exported import declaration '{0}' is assigned type that is using inaccessible module '{1}'.": { "code": 2184, "category": DiagnosticCategory.Error },
"Exported import declaration '{0}' is assigned container that is or is using inaccessible module '{1}'.": { "code": 2185, "category": DiagnosticCategory.Error },
"Type name '{0}' in extends clause does not reference constructor function for '{1}'.": { "code": 2186, "category": DiagnosticCategory.Error },
"Internal module reference '{0}' in import declaration does not reference module instance for '{1}'.": { "code": 2187, "category": DiagnosticCategory.Error },
"Module '{0}' cannot merge with previous declaration of '{1}' in a different file '{2}'.": { "code": 2188, "category": DiagnosticCategory.Error },
"Interface '{0}' cannot simultaneously extend types '{1}' and '{2}':{NL}{3}": { "code": 2189, "category": DiagnosticCategory.Error },
"Initializer of parameter '{0}' cannot reference identifier '{1}' declared after it.": { "code": 2190, "category": DiagnosticCategory.Error },
"Ambient external module declaration cannot be reopened.": { "code": 2191, "category": DiagnosticCategory.Error },
"All declarations of merged declaration '{0}' must be exported or not exported.": { "code": 2192, "category": DiagnosticCategory.Error },
"'super' cannot be referenced in constructor arguments.": { "code": 2193, "category": DiagnosticCategory.Error },
"Return type of constructor signature must be assignable to the instance type of the class.": { "code": 2194, "category": DiagnosticCategory.Error },
"Ambient external module declaration must be defined in global context.": { "code": 2195, "category": DiagnosticCategory.Error },
"Ambient external module declaration cannot specify relative module name.": { "code": 2196, "category": DiagnosticCategory.Error },
"Import declaration in an ambient external module declaration cannot reference external module through relative external module name.": { "code": 2197, "category": DiagnosticCategory.Error },
"No best common type exists among return expressions.": { "code": 2198, "category": DiagnosticCategory.Error },
"Import declaration cannot refer to external module reference when --noResolve option is set.": { "code": 2199, "category": DiagnosticCategory.Error },
"Duplicate identifier '_this'. Compiler uses variable declaration '_this' to capture 'this' reference.": { "code": 2200, "category": DiagnosticCategory.Error },
"Duplicate identifier '_super'. Compiler uses '_super' to capture base class reference.": { "code": 2205, "category": DiagnosticCategory.Error },
"Expression resolves to variable declaration '_this' that compiler uses to capture 'this' reference.": { "code": 2206, "category": DiagnosticCategory.Error },
"Expression resolves to '_super' that compiler uses to capture base class reference.": { "code": 2207, "category": DiagnosticCategory.Error },
"TypeParameter '{0}' of constructor signature from exported interface has or is using private type '{1}'.": { "code": 2208, "category": DiagnosticCategory.Error },
"TypeParameter '{0}' of call signature from exported interface has or is using private type '{1}'.": { "code": 2209, "category": DiagnosticCategory.Error },
"TypeParameter '{0}' of public static method from exported class has or is using private type '{1}'.": { "code": 2210, "category": DiagnosticCategory.Error },
"TypeParameter '{0}' of public method from exported class has or is using private type '{1}'.": { "code": 2211, "category": DiagnosticCategory.Error },
"TypeParameter '{0}' of method from exported interface has or is using private type '{1}'.": { "code": 2212, "category": DiagnosticCategory.Error },
"TypeParameter '{0}' of exported function has or is using private type '{1}'.": { "code": 2213, "category": DiagnosticCategory.Error },
"TypeParameter '{0}' of constructor signature from exported interface is using inaccessible module {1}.": { "code": 2214, "category": DiagnosticCategory.Error },
"TypeParameter '{0}' of call signature from exported interface is using inaccessible module {1}": { "code": 2215, "category": DiagnosticCategory.Error },
"TypeParameter '{0}' of public static method from exported class is using inaccessible module {1}.": { "code": 2216, "category": DiagnosticCategory.Error },
"TypeParameter '{0}' of public method from exported class is using inaccessible module {1}.": { "code": 2217, "category": DiagnosticCategory.Error },
"TypeParameter '{0}' of method from exported interface is using inaccessible module {1}.": { "code": 2218, "category": DiagnosticCategory.Error },
"TypeParameter '{0}' of exported function is using inaccessible module {1}.": { "code": 2219, "category": DiagnosticCategory.Error },
"TypeParameter '{0}' of exported class has or is using private type '{1}'.": { "code": 2220, "category": DiagnosticCategory.Error },
"TypeParameter '{0}' of exported interface has or is using private type '{1}'.": { "code": 2221, "category": DiagnosticCategory.Error },
"TypeParameter '{0}' of exported class is using inaccessible module {1}.": { "code": 2222, "category": DiagnosticCategory.Error },
"TypeParameter '{0}' of exported interface is using inaccessible module {1}.": { "code": 2223, "category": DiagnosticCategory.Error },
"Duplicate identifier '_i'. Compiler uses '_i' to initialize rest parameter.": { "code": 2224, "category": DiagnosticCategory.Error },
"Duplicate identifier 'arguments'. Compiler uses 'arguments' to initialize rest parameters.": { "code": 2225, "category": DiagnosticCategory.Error },
"No best common type exists between '{0}' and '{1}'.": { "code": 2226, "category": DiagnosticCategory.Error },
"No best common type exists between '{0}', '{1}', and '{2}'.": { "code": 2227, "category": DiagnosticCategory.Error },
"Duplicate identifier '{0}'. Compiler reserves name '{1}' in top level scope of an external module.": { "code": 2228, "category": DiagnosticCategory.Error },
"Constraint of a type parameter cannot reference any type parameter from the same type parameter list.": { "code": 2229, "category": DiagnosticCategory.Error },
"Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor.": { "code": 2230, "category": DiagnosticCategory.Error },
"Parameter '{0}' cannot be referenced in its initializer.": { "code": 2231, "category": DiagnosticCategory.Error },
"Duplicate string index signature.": { "code": 2232, "category": DiagnosticCategory.Error },
"Duplicate number index signature.": { "code": 2233, "category": DiagnosticCategory.Error },
"All declarations of an interface must have identical type parameters.": { "code": 2234, "category": DiagnosticCategory.Error },
"Expression resolves to variable declaration '_i' that compiler uses to initialize rest parameter.": { "code": 2235, "category": DiagnosticCategory.Error },
"Neither type '{0}' nor type '{1}' is assignable to the other.": { "code": 2236, "category": DiagnosticCategory.Error },
"Neither type '{0}' nor type '{1}' is assignable to the other:{NL}{2}": { "code": 2237, "category": DiagnosticCategory.Error },
"Duplicate function implementation.": { "code": 2237, "category": DiagnosticCategory.Error },
"Function implementation expected.": { "code": 2238, "category": DiagnosticCategory.Error },
"Function overload name must be '{0}'.": { "code": 2239, "category": DiagnosticCategory.Error },
"Constructor implementation expected.": { "code": 2240, "category": DiagnosticCategory.Error },
"Class name cannot be '{0}'.": { "code": 2241, "category": DiagnosticCategory.Error },
"Interface name cannot be '{0}'.": { "code": 2242, "category": DiagnosticCategory.Error },
"Enum name cannot be '{0}'.": { "code": 2243, "category": DiagnosticCategory.Error },
"A module cannot have multiple export assignments.": { "code": 2244, "category": DiagnosticCategory.Error },
"Export assignment not allowed in module with exported element.": { "code": 2245, "category": DiagnosticCategory.Error },
"A parameter property is only allowed in a constructor implementation.": { "code": 2246, "category": DiagnosticCategory.Error },
"Function overload must be static.": { "code": 2247, "category": DiagnosticCategory.Error },
"Function overload must not be static.": { "code": 2248, "category": DiagnosticCategory.Error },
"Type '{0}' is missing property '{1}' from type '{2}'.": { "code": 4000, "category": DiagnosticCategory.NoPrefix },
"Types of property '{0}' of types '{1}' and '{2}' are incompatible.": { "code": 4001, "category": DiagnosticCategory.NoPrefix },
"Types of property '{0}' of types '{1}' and '{2}' are incompatible:{NL}{3}": { "code": 4002, "category": DiagnosticCategory.NoPrefix },
"Property '{0}' defined as private in type '{1}' is defined as public in type '{2}'.": { "code": 4003, "category": DiagnosticCategory.NoPrefix },
"Property '{0}' defined as public in type '{1}' is defined as private in type '{2}'.": { "code": 4004, "category": DiagnosticCategory.NoPrefix },
"Types '{0}' and '{1}' define property '{2}' as private.": { "code": 4005, "category": DiagnosticCategory.NoPrefix },
"Call signatures of types '{0}' and '{1}' are incompatible.": { "code": 4006, "category": DiagnosticCategory.NoPrefix },
"Call signatures of types '{0}' and '{1}' are incompatible:{NL}{2}": { "code": 4007, "category": DiagnosticCategory.NoPrefix },
"Type '{0}' requires a call signature, but type '{1}' lacks one.": { "code": 4008, "category": DiagnosticCategory.NoPrefix },
"Construct signatures of types '{0}' and '{1}' are incompatible.": { "code": 4009, "category": DiagnosticCategory.NoPrefix },
"Construct signatures of types '{0}' and '{1}' are incompatible:{NL}{2}": { "code": 4010, "category": DiagnosticCategory.NoPrefix },
"Type '{0}' requires a construct signature, but type '{1}' lacks one.": { "code": 4011, "category": DiagnosticCategory.NoPrefix },
"Index signatures of types '{0}' and '{1}' are incompatible.": { "code": 4012, "category": DiagnosticCategory.NoPrefix },
"Index signatures of types '{0}' and '{1}' are incompatible:{NL}{2}": { "code": 4013, "category": DiagnosticCategory.NoPrefix },
"Call signature expects {0} or fewer parameters.": { "code": 4014, "category": DiagnosticCategory.NoPrefix },
"Could not apply type '{0}' to argument {1} which is of type '{2}'.": { "code": 4015, "category": DiagnosticCategory.NoPrefix },
"Class '{0}' defines instance member accessor '{1}', but extended class '{2}' defines it as instance member function.": { "code": 4016, "category": DiagnosticCategory.NoPrefix },
"Class '{0}' defines instance member property '{1}', but extended class '{2}' defines it as instance member function.": { "code": 4017, "category": DiagnosticCategory.NoPrefix },
"Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member accessor.": { "code": 4018, "category": DiagnosticCategory.NoPrefix },
"Class '{0}' defines instance member function '{1}', but extended class '{2}' defines it as instance member property.": { "code": 4019, "category": DiagnosticCategory.NoPrefix },
"Types of static property '{0}' of class '{1}' and class '{2}' are incompatible.": { "code": 4020, "category": DiagnosticCategory.NoPrefix },
"Types of static property '{0}' of class '{1}' and class '{2}' are incompatible:{NL}{3}": { "code": 4021, "category": DiagnosticCategory.NoPrefix },
"Type reference cannot refer to container '{0}'.": { "code": 4022, "category": DiagnosticCategory.Error },
"Type reference must refer to type.": { "code": 4023, "category": DiagnosticCategory.Error },
"In enums with multiple declarations only one declaration can omit an initializer for the first enum element.": { "code": 4024, "category": DiagnosticCategory.Error },
" (+ {0} overload(s))": { "code": 4025, "category": DiagnosticCategory.Message },
"Variable declaration cannot have the same name as an import declaration.": { "code": 4026, "category": DiagnosticCategory.Error },
"Signature expected {0} type arguments, got {1} instead.": { "code": 4027, "category": DiagnosticCategory.Error },
"Property '{0}' defined as optional in type '{1}', but is required in type '{2}'.": { "code": 4028, "category": DiagnosticCategory.NoPrefix },
"Types '{0}' and '{1}' originating in infinitely expanding type reference do not refer to same named type.": { "code": 4029, "category": DiagnosticCategory.NoPrefix },
"Types '{0}' and '{1}' originating in infinitely expanding type reference have incompatible type arguments.": { "code": 4030, "category": DiagnosticCategory.NoPrefix },
"Types '{0}' and '{1}' originating in infinitely expanding type reference have incompatible type arguments:{NL}{2}": { "code": 4031, "category": DiagnosticCategory.NoPrefix },
"Named properties '{0}' of types '{1}' and '{2}' are not identical.": { "code": 4032, "category": DiagnosticCategory.NoPrefix },
"Types of string indexer of types '{0}' and '{1}' are not identical.": { "code": 4033, "category": DiagnosticCategory.NoPrefix },
"Types of number indexer of types '{0}' and '{1}' are not identical.": { "code": 4034, "category": DiagnosticCategory.NoPrefix },
"Type of number indexer in type '{0}' is not assignable to string indexer type in type '{1}'.{NL}{2}": { "code": 4035, "category": DiagnosticCategory.NoPrefix },
"Type of property '{0}' in type '{1}' is not assignable to string indexer type in type '{2}'.{NL}{3}": { "code": 4036, "category": DiagnosticCategory.NoPrefix },
"Type of property '{0}' in type '{1}' is not assignable to number indexer type in type '{2}'.{NL}{3}": { "code": 4037, "category": DiagnosticCategory.NoPrefix },
"Static property '{0}' defined as private in type '{1}' is defined as public in type '{2}'.": { "code": 4038, "category": DiagnosticCategory.NoPrefix },
"Static property '{0}' defined as public in type '{1}' is defined as private in type '{2}'.": { "code": 4039, "category": DiagnosticCategory.NoPrefix },
"Types '{0}' and '{1}' define static property '{2}' as private.": { "code": 4040, "category": DiagnosticCategory.NoPrefix },
"Current host does not support '{0}' option.": { "code": 5001, "category": DiagnosticCategory.Error },
"ECMAScript target version '{0}' not supported. Specify a valid target version: '{1}' (default), or '{2}'": { "code": 5002, "category": DiagnosticCategory.Error },
"Argument for '{0}' option must be '{1}' or '{2}'": { "code": 5003, "category": DiagnosticCategory.Error },
"Could not find file: '{0}'.": { "code": 5004, "category": DiagnosticCategory.Error },
"A file cannot have a reference to itself.": { "code": 5006, "category": DiagnosticCategory.Error },
"Cannot resolve referenced file: '{0}'.": { "code": 5007, "category": DiagnosticCategory.Error },
"Cannot find the common subdirectory path for the input files.": { "code": 5009, "category": DiagnosticCategory.Error },
"Emit Error: {0}.": { "code": 5011, "category": DiagnosticCategory.Error },
"Cannot read file '{0}': {1}": { "code": 5012, "category": DiagnosticCategory.Error },
"Unsupported file encoding.": { "code": 5013, "category": DiagnosticCategory.NoPrefix },
"Locale must be of the form <language> or <language>-<territory>. For example '{0}' or '{1}'.": { "code": 5014, "category": DiagnosticCategory.Error },
"Unsupported locale: '{0}'.": { "code": 5015, "category": DiagnosticCategory.Error },
"Execution Failed.{NL}": { "code": 5016, "category": DiagnosticCategory.Error },
"Invalid call to 'up'": { "code": 5019, "category": DiagnosticCategory.Error },
"Invalid call to 'down'": { "code": 5020, "category": DiagnosticCategory.Error },
"Base64 value '{0}' finished with a continuation bit.": { "code": 5021, "category": DiagnosticCategory.Error },
"Unknown compiler option '{0}'": { "code": 5023, "category": DiagnosticCategory.Error },
"Expected {0} arguments to message, got {1} instead.": { "code": 5024, "category": DiagnosticCategory.Error },
"Expected the message '{0}' to have {1} arguments, but it had {2}": { "code": 5025, "category": DiagnosticCategory.Error },
"Could not delete file '{0}'": { "code": 5034, "category": DiagnosticCategory.Error },
"Could not create directory '{0}'": { "code": 5035, "category": DiagnosticCategory.Error },
"Error while executing file '{0}': ": { "code": 5036, "category": DiagnosticCategory.Error },
"Cannot compile external modules unless the '--module' flag is provided.": { "code": 5037, "category": DiagnosticCategory.Error },
"Option mapRoot cannot be specified without specifying sourcemap option.": { "code": 5038, "category": DiagnosticCategory.Error },
"Option sourceRoot cannot be specified without specifying sourcemap option.": { "code": 5039, "category": DiagnosticCategory.Error },
"Options mapRoot and sourceRoot cannot be specified without specifying sourcemap option.": { "code": 5040, "category": DiagnosticCategory.Error },
"Option '{0}' specified without '{1}'": { "code": 5041, "category": DiagnosticCategory.Error },
"'codepage' option not supported on current platform.": { "code": 5042, "category": DiagnosticCategory.Error },
"Concatenate and emit output to single file.": { "code": 6001, "category": DiagnosticCategory.Message },
"Generates corresponding {0} file.": { "code": 6002, "category": DiagnosticCategory.Message },
"Specifies the location where debugger should locate map files instead of generated locations.": { "code": 6003, "category": DiagnosticCategory.Message },
"Specifies the location where debugger should locate TypeScript files instead of source locations.": { "code": 6004, "category": DiagnosticCategory.Message },
"Watch input files.": { "code": 6005, "category": DiagnosticCategory.Message },
"Redirect output structure to the directory.": { "code": 6006, "category": DiagnosticCategory.Message },
"Do not emit comments to output.": { "code": 6009, "category": DiagnosticCategory.Message },
"Skip resolution and preprocessing.": { "code": 6010, "category": DiagnosticCategory.Message },
"Specify ECMAScript target version: '{0}' (default), or '{1}'": { "code": 6015, "category": DiagnosticCategory.Message },
"Specify module code generation: '{0}' or '{1}'": { "code": 6016, "category": DiagnosticCategory.Message },
"Print this message.": { "code": 6017, "category": DiagnosticCategory.Message },
"Print the compiler's version: {0}": { "code": 6019, "category": DiagnosticCategory.Message },
"Allow use of deprecated '{0}' keyword when referencing an external module.": { "code": 6021, "category": DiagnosticCategory.Message },
"Specify locale for errors and messages. For example '{0}' or '{1}'": { "code": 6022, "category": DiagnosticCategory.Message },
"Syntax: {0}": { "code": 6023, "category": DiagnosticCategory.Message },
"options": { "code": 6024, "category": DiagnosticCategory.Message },
"file1": { "code": 6025, "category": DiagnosticCategory.Message },
"Examples:": { "code": 6026, "category": DiagnosticCategory.Message },
"Options:": { "code": 6027, "category": DiagnosticCategory.Message },
"Insert command line options and files from a file.": { "code": 6030, "category": DiagnosticCategory.Message },
"Version {0}": { "code": 6029, "category": DiagnosticCategory.Message },
"Use the '{0}' flag to see options.": { "code": 6031, "category": DiagnosticCategory.Message },
"{NL}Recompiling ({0}):": { "code": 6032, "category": DiagnosticCategory.Message },
"STRING": { "code": 6033, "category": DiagnosticCategory.Message },
"KIND": { "code": 6034, "category": DiagnosticCategory.Message },
"file2": { "code": 6035, "category": DiagnosticCategory.Message },
"VERSION": { "code": 6036, "category": DiagnosticCategory.Message },
"LOCATION": { "code": 6037, "category": DiagnosticCategory.Message },
"DIRECTORY": { "code": 6038, "category": DiagnosticCategory.Message },
"NUMBER": { "code": 6039, "category": DiagnosticCategory.Message },
"Specify the codepage to use when opening source files.": { "code": 6040, "category": DiagnosticCategory.Message },
"Additional locations:": { "code": 6041, "category": DiagnosticCategory.Message },
"This version of the Javascript runtime does not support the '{0}' function.": { "code": 7000, "category": DiagnosticCategory.Error },
"Unknown rule.": { "code": 7002, "category": DiagnosticCategory.Error },
"Invalid line number ({0})": { "code": 7003, "category": DiagnosticCategory.Error },
"Warn on expressions and declarations with an implied 'any' type.": { "code": 7004, "category": DiagnosticCategory.Message },
"Variable '{0}' implicitly has an 'any' type.": { "code": 7005, "category": DiagnosticCategory.Error },
"Parameter '{0}' of '{1}' implicitly has an 'any' type.": { "code": 7006, "category": DiagnosticCategory.Error },
"Parameter '{0}' of function type implicitly has an 'any' type.": { "code": 7007, "category": DiagnosticCategory.Error },
"Member '{0}' of object type implicitly has an 'any' type.": { "code": 7008, "category": DiagnosticCategory.Error },
"'new' expression, which lacks a constructor signature, implicitly has an 'any' type.": { "code": 7009, "category": DiagnosticCategory.Error },
"'{0}', which lacks return-type annotation, implicitly has an 'any' return type.": { "code": 7010, "category": DiagnosticCategory.Error },
"Function expression, which lacks return-type annotation, implicitly has an 'any' return type.": { "code": 7011, "category": DiagnosticCategory.Error },
"Parameter '{0}' of lambda function implicitly has an 'any' type.": { "code": 7012, "category": DiagnosticCategory.Error },
"Constructor signature, which lacks return-type annotation, implicitly has an 'any' return type.": { "code": 7013, "category": DiagnosticCategory.Error },
"Lambda Function, which lacks return-type annotation, implicitly has an 'any' return type.": { "code": 7014, "category": DiagnosticCategory.Error },
"Array Literal implicitly has an 'any' type from widening.": { "code": 7015, "category": DiagnosticCategory.Error },
"'{0}', which lacks 'get' accessor and parameter type annotation on 'set' accessor, implicitly has an 'any' type.": { "code": 7016, "category": DiagnosticCategory.Error },
"Index signature of object type implicitly has an 'any' type.": { "code": 7017, "category": DiagnosticCategory.Error },
"Object literal's property '{0}' implicitly has an 'any' type from widening.": { "code": 7018, "category": DiagnosticCategory.Error },
};
}
File diff suppressed because it is too large Load Diff
+2
View File
@@ -0,0 +1,2 @@
/// <reference path='diagnosticCode.generated.ts' />
/// <reference path='diagnosticInformationMap.generated.ts' />
+1929 -132
View File
File diff suppressed because it is too large Load Diff
+804 -50
View File
@@ -1,18 +1,26 @@
/// <reference path="services.ts"/>
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
/// <reference path='services.ts' />
/// <reference path='compiler\pathUtils.ts' />
/// <reference path='compiler\precompile.ts' />
var debugObjectHost = (<any>this);
module ts {
export interface LanguageServiceShimHost {
log(s: string): void;
getCompilationSettings(): string;
getScriptFileNames(): string;
getScriptVersion(fileName: string): string;
getScriptIsOpen(fileName: string): boolean;
getScriptByteOrderMark(fileName: string): number;
getScriptSnapshot(fileName: string): ScriptSnapshotShim;
getLocalizedDiagnosticMessages(): string;
// getCancellationToken(): CancellationToken
}
export interface ScriptSnapshotShim {
// Get's a portion of the script snapshot specified by [start, end).
getText(start: number, end: number): string;
@@ -28,10 +36,230 @@ module ts {
// { span: { start: number; length: number }; newLength: number }
//
// Or null value if there was no change.
getChangeRange(oldSnapshot: ScriptSnapshotShim): string;
getTextChangeRangeSinceVersion(scriptVersion: number): string;
}
class ScriptSnapshotShimAdapter implements IScriptSnapshot {
//
// Public interface of the host of a language service shim instance.
//
export interface LanguageServiceShimHost extends Logger {
getCompilationSettings(): string;
// Returns a JSON encoded value of the type:
// string[]
getScriptFileNames(): string;
getScriptVersion(fileName: string): number;
getScriptIsOpen(fileName: string): boolean;
getScriptByteOrderMark(fileName: string): number;
getScriptSnapshot(fileName: string): ScriptSnapshotShim;
getLocalizedDiagnosticMessages(): string;
getCancellationToken(): CancellationToken;
}
//
// Public interface of of a language service instance shim.
//
export interface ShimFactory {
registerShim(shim: Shim): void;
unregisterShim(shim: Shim): void;
}
export interface Shim {
dispose(dummy: any): void;
}
export interface LanguageServiceShim extends Shim {
languageService: LanguageService;
dispose(dummy: any): void;
refresh(throwOnError: boolean): void;
cleanupSemanticCache(): void;
getSyntacticDiagnostics(fileName: string): string;
getSemanticDiagnostics(fileName: string): string;
getCompilerOptionsDiagnostics(): string;
getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean): string;
getCompletionEntryDetails(fileName: string, position: number, entryName: string): string;
getTypeAtPosition(fileName: string, position: number): string;
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): string;
getBreakpointStatementAtPosition(fileName: string, position: number): string;
getSignatureAtPosition(fileName: string, position: number): string;
// Returns a JSON encoded value of the type:
// { fileName: string; minChar: number; limChar: number; kind: string; name: string; containerKind: string; containerName: string }
//
// Or null value if no definition can be found.
getDefinitionAtPosition(fileName: string, position: number): string;
// Returns a JSON encoded value of the type:
// { fileName: string; minChar: number; limChar: number; isWriteAccess: boolean }[]
getReferencesAtPosition(fileName: string, position: number): string;
// Returns a JSON encoded value of the type:
// { fileName: string; minChar: number; limChar: number; isWriteAccess: boolean }[]
getOccurrencesAtPosition(fileName: string, position: number): string;
// Returns a JSON encoded value of the type:
// { fileName: string; minChar: number; limChar: number; isWriteAccess: boolean }[]
getImplementorsAtPosition(fileName: string, position: number): string;
// Returns a JSON encoded value of the type:
// { name: string; kind: string; kindModifiers: string; containerName: string; containerKind: string; matchKind: string; fileName: string; minChar: number; limChar: number; } [] = [];
getNavigateToItems(searchValue: string): string;
// Returns a JSON encoded value of the type:
// { name: string; kind: string; kindModifiers: string; containerName: string; containerKind: string; matchKind: string; fileName: string; minChar: number; limChar: number; } [] = [];
getScriptLexicalStructure(fileName: string): string;
// Returns a JSON encoded value of the type:
// { name: string; kind: string; kindModifiers: string; containerName: string; containerKind: string; matchKind: string; fileName: string; minChar: number; limChar: number; } [] = [];
getOutliningRegions(fileName: string): string;
getBraceMatchingAtPosition(fileName: string, position: number): string;
getIndentationAtPosition(fileName: string, position: number, options: string/*Services.EditorOptions*/): string;
getFormattingEditsForRange(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string;
getFormattingEditsForDocument(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string;
getFormattingEditsOnPaste(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string;
getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: string/*Services.FormatCodeOptions*/): string;
getEmitOutput(fileName: string): string;
}
export interface ClassifierShim extends Shim {
getClassificationsForLine(text: string, lexState: EndOfLineState): string;
}
export interface CoreServicesShim extends Shim {
getPreProcessedFileInfo(fileName: string, sourceText: TypeScript.IScriptSnapshot): string;
getDefaultCompilationSettings(): string;
}
/// TODO: delete this, it is only needed untill the VS interface is updated
enum LanguageVersion {
EcmaScript3 = 0,
EcmaScript5 = 1,
}
enum ModuleGenTarget {
Unspecified = 0,
Synchronous = 1,
Asynchronous = 2,
}
interface CompilationSettings {
propagateEnumConstants?: boolean;
removeComments?: boolean;
watch?: boolean;
noResolve?: boolean;
allowAutomaticSemicolonInsertion?: boolean;
noImplicitAny?: boolean;
noLib?: boolean;
codeGenTarget?: LanguageVersion;
moduleGenTarget?: ModuleGenTarget;
outFileOption?: string;
outDirOption?: string;
mapSourceFiles?: boolean;
mapRoot?: string;
sourceRoot?: string;
generateDeclarationFiles?: boolean;
useCaseSensitiveFileResolution?: boolean;
gatherDiagnostics?: boolean;
codepage?: number;
}
function languageVersionToScriptTarget(languageVersion: LanguageVersion): ScriptTarget {
if (typeof languageVersion === "undefined") return undefined;
switch (languageVersion) {
case LanguageVersion.EcmaScript3: return ScriptTarget.ES3;
case LanguageVersion.EcmaScript5: return ScriptTarget.ES5;
default: throw Error("unsuported LanguageVersion value: " + languageVersion);
}
}
function moduleGenTargetToModuleKind(moduleGenTarget: ModuleGenTarget): ModuleKind {
if (typeof moduleGenTarget === "undefined") return undefined;
switch (moduleGenTarget) {
case ModuleGenTarget.Asynchronous: return ModuleKind.AMD;
case ModuleGenTarget.Synchronous: return ModuleKind.CommonJS;
case ModuleGenTarget.Unspecified: return ModuleKind.None;
default: throw Error("unsuported ModuleGenTarget value: " + moduleGenTarget);
}
}
function scriptTargetTolanguageVersion(scriptTarget: ScriptTarget): LanguageVersion {
if (typeof scriptTarget === "undefined") return undefined;
switch (scriptTarget) {
case ScriptTarget.ES3: return LanguageVersion.EcmaScript3;
case ScriptTarget.ES5: return LanguageVersion.EcmaScript5;
default: throw Error("unsuported ScriptTarget value: " + scriptTarget);
}
}
function moduleKindToModuleGenTarget(moduleKind: ModuleKind): ModuleGenTarget {
if (typeof moduleKind === "undefined") return undefined;
switch (moduleKind) {
case ModuleKind.AMD: return ModuleGenTarget.Asynchronous;
case ModuleKind.CommonJS: return ModuleGenTarget.Synchronous;
case ModuleKind.None: return ModuleGenTarget.Unspecified;
default: throw Error("unsuported ModuleKind value: " + moduleKind);
}
}
function compilationSettingsToCompilerOptions(settings: CompilationSettings): CompilerOptions {
// TODO: we should not be converting, but use options all the way
var options: CompilerOptions = {};
//options.propagateEnumConstants = settings.propagateEnumConstants;
options.removeComments = settings.removeComments;
options.noResolve = settings.noResolve;
options.noImplicitAny = settings.noImplicitAny;
options.noLib = settings.noLib;
options.target = languageVersionToScriptTarget(settings.codeGenTarget);
options.module = moduleGenTargetToModuleKind(settings.moduleGenTarget);
options.out = settings.outFileOption;
options.outDir = settings.outDirOption;
options.sourceMap = settings.mapSourceFiles;
options.mapRoot = settings.mapRoot;
options.sourceRoot = settings.sourceRoot;
options.declaration = settings.generateDeclarationFiles;
//options.useCaseSensitiveFileResolution = settings.useCaseSensitiveFileResolution;
options.codepage = settings.codepage;
return options;
}
function compilerOptionsToCompilationSettings(options: CompilerOptions): CompilationSettings {
var settings: CompilationSettings = {};
//options.propagateEnumConstants = settings.propagateEnumConstants;
settings.removeComments = options.removeComments;
settings.noResolve = options.noResolve;
settings.noImplicitAny = options.noImplicitAny;
settings.noLib = options.noLib;
settings.codeGenTarget = scriptTargetTolanguageVersion(options.target);
settings.moduleGenTarget = moduleKindToModuleGenTarget(options.module);
settings.outFileOption = options.out;
settings.outDirOption = options.outDir;
settings.mapSourceFiles = options.sourceMap;
settings.mapRoot = options.mapRoot;
settings.sourceRoot = options.sourceRoot;
settings.generateDeclarationFiles = options.declaration;
// settings.useCaseSensitiveFileResolution = options.useCaseSensitiveFileResolution;
settings.codepage = options.codepage;
return settings;
}
function logInternalError(logger: Logger, err: Error) {
logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message);
}
class ScriptSnapshotShimAdapter implements TypeScript.IScriptSnapshot {
private lineStartPositions: number[] = null;
constructor(private scriptSnapshotShim: ScriptSnapshotShim) {
@@ -53,41 +281,42 @@ module ts {
return this.lineStartPositions;
}
public getChangeRange(scriptSnapshot: IScriptSnapshot): TextChangeRange {
function createTextRange(start: number, length: number) {
function createSpan(start: number, length: number) {
return {
start: () => start,
end: () => start + length,
lenth: () => length,
isEmpty: () => length === 0
};
}
return {
span: () => createSpan(start, length),
newLength: () => length,
newSpan: () => createSpan(start, length),
isUnchanged: () => length === 0
};
}
var encoded = this.scriptSnapshotShim.getChangeRange((<ScriptSnapshotShimAdapter>scriptSnapshot).scriptSnapshotShim);
public getTextChangeRangeSinceVersion(scriptVersion: number): TypeScript.TextChangeRange {
var encoded = this.scriptSnapshotShim.getTextChangeRangeSinceVersion(scriptVersion);
if (encoded == null) {
return null;
}
var decoded: { span: { start: number; length: number; }; newLength: number; } = JSON.parse(encoded);
return createTextRange(decoded.span.start, decoded.span.length);
return new TypeScript.TextChangeRange(
new TypeScript.TextSpan(decoded.span.start, decoded.span.length), decoded.newLength);
}
}
export class LanguageServiceShimHostAdapter implements LanguageServiceHost {
class LanguageServiceShimHostAdapter implements LanguageServiceHost {
constructor(private shimHost: LanguageServiceShimHost) {
}
public information(): boolean {
return this.shimHost.information();
}
public debug(): boolean {
return this.shimHost.debug();
}
public warning(): boolean {
return this.shimHost.warning();
}
public error(): boolean {
return this.shimHost.error();
}
public fatal(): boolean {
return this.shimHost.fatal();
}
public log(s: string): void {
this.shimHost.log(s);
}
@@ -95,10 +324,18 @@ module ts {
public getCompilationSettings(): CompilerOptions {
var settingsJson = this.shimHost.getCompilationSettings();
if (settingsJson == null || settingsJson == "") {
return {};
throw Error("LanguageServiceShimHostAdapter.getCompilationSettings: empty compilationSettings");
return null;
}
var settings: CompilerOptions = JSON.parse(<any>settingsJson);
return settings;
var options = compilationSettingsToCompilerOptions(<CompilerOptions>JSON.parse(<any>settingsJson));
/// TODO: this should be pushed into VS.
/// We can not ask the LS instance to resolve, as this will lead to asking the host about files it does not know about,
/// something it is not desinged to handle. for now make sure we never get a "noresolve == false".
/// This value should not matter, as the host runs resolution logic independentlly
options.noResolve = true;
return options;
}
public getScriptFileNames(): string[] {
@@ -106,11 +343,11 @@ module ts {
return JSON.parse(encoded);
}
public getScriptSnapshot(fileName: string): IScriptSnapshot {
public getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot {
return new ScriptSnapshotShimAdapter(this.shimHost.getScriptSnapshot(fileName));
}
public getScriptVersion(fileName: string): string {
public getScriptVersion(fileName: string): number {
return this.shimHost.getScriptVersion(fileName);
}
@@ -136,10 +373,527 @@ module ts {
}
}
//public getCancellationToken(): CancellationToken {
// return this.shimHost.getCancellationToken();
//}
public getCancellationToken(): CancellationToken {
return this.shimHost.getCancellationToken();
}
}
}
function simpleForwardCall(logger: Logger, actionDescription: string, action: () => any): any {
logger.log(actionDescription);
var start = Date.now();
var result = action();
var end = Date.now();
logger.log(actionDescription + " completed in " + (end - start) + " msec");
if (typeof (result) === "string") {
var str = <string>result;
if (str.length > 128) {
str = str.substring(0, 128) + "...";
}
logger.log(" result.length=" + str.length + ", result='" + JSON.stringify(str) + "'");
}
return result;
}
function forwardJSONCall(logger: Logger, actionDescription: string, action: () => any): string {
try {
var result = simpleForwardCall(logger, actionDescription, action);
return JSON.stringify({ result: result });
}
catch (err) {
if (err instanceof OperationCanceledException) {
return JSON.stringify({ canceled: true });
}
logInternalError(logger, err);
err.description = actionDescription;
return JSON.stringify({ error: err });
}
}
class ShimBase implements Shim {
constructor(private factory: ShimFactory) {
factory.registerShim(this);
}
public dispose(dummy: any): void {
this.factory.unregisterShim(this);
}
}
class LanguageServiceShimObject extends ShimBase implements LanguageServiceShim {
private logger: Logger;
constructor(factory: ShimFactory,
private host: LanguageServiceShimHost,
public languageService: LanguageService) {
super(factory);
this.logger = this.host;
}
public forwardJSONCall(actionDescription: string, action: () => any): string {
return forwardJSONCall(this.logger, actionDescription, action);
}
// DISPOSE
// Ensure (almost) determinstic release of internal Javascript resources when
// some external native objects holds onto us (e.g. Com/Interop).
public dispose(dummy: any): void {
this.logger.log("dispose()");
this.languageService.dispose();
this.languageService = null;
// force a GC
if (debugObjectHost && debugObjectHost.CollectGarbage) {
debugObjectHost.CollectGarbage();
this.logger.log("CollectGarbage()");
}
this.logger = null;
super.dispose(dummy);
}
// REFRESH
// Update the list of scripts known to the compiler
public refresh(throwOnError: boolean): void {
this.forwardJSONCall(
"refresh(" + throwOnError + ")",
() => {
this.languageService.refresh();
return <any>null;
});
}
public cleanupSemanticCache(): void {
this.forwardJSONCall(
"cleanupSemanticCache()",
() => {
this.languageService.cleanupSemanticCache();
return <any>null;
});
}
/// SQUIGGLES
///
private static realizeDiagnostic(diagnostic: Diagnostic): { message: string; start: number; length: number; category: string; } {
return {
message: diagnostic.messageText,
start: diagnostic.start,
length: diagnostic.length,
/// TODO: no need for the tolowerCase call
category: DiagnosticCategory[diagnostic.category].toLowerCase()
};
}
private realizeDiagnosticWithFileName(diagnostic: Diagnostic): { fileName: string; message: string; start: number; length: number; category: string; } {
return {
fileName: diagnostic.file.filename,
message: diagnostic.messageText,
start: diagnostic.start,
length: diagnostic.length,
/// TODO: no need for the tolowerCase call
category: DiagnosticCategory[diagnostic.category].toLowerCase()
};
}
public getSyntacticDiagnostics(fileName: string): string {
return this.forwardJSONCall(
"getSyntacticDiagnostics(\"" + fileName + "\")",
() => {
var errors = this.languageService.getSyntacticDiagnostics(fileName);
return errors.map(LanguageServiceShimObject.realizeDiagnostic);
});
}
public getSemanticDiagnostics(fileName: string): string {
return this.forwardJSONCall(
"getSemanticDiagnostics(\"" + fileName + "\")",
() => {
var errors = this.languageService.getSemanticDiagnostics(fileName);
return errors.map(LanguageServiceShimObject.realizeDiagnostic);
});
}
public getCompilerOptionsDiagnostics(): string {
return this.forwardJSONCall(
"getCompilerOptionsDiagnostics()",
() => {
var errors = this.languageService.getCompilerOptionsDiagnostics();
return errors.map(d => this.realizeDiagnosticWithFileName(d))
});
}
/// QUICKINFO
/// Computes a string representation of the type at the requested position
/// in the active file.
public getTypeAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getTypeAtPosition(\"" + fileName + "\", " + position + ")",
() => {
var typeInfo = this.languageService.getTypeAtPosition(fileName, position);
return typeInfo;
});
}
/// NAMEORDOTTEDNAMESPAN
/// Computes span information of the name or dotted name at the requested position
// in the active file.
public getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): string {
return this.forwardJSONCall(
"getNameOrDottedNameSpan(\"" + fileName + "\", " + startPos + ", " + endPos + ")",
() => {
var spanInfo = this.languageService.getNameOrDottedNameSpan(fileName, startPos, endPos);
return spanInfo;
});
}
/// STATEMENTSPAN
/// Computes span information of statement at the requested position in the active file.
public getBreakpointStatementAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getBreakpointStatementAtPosition(\"" + fileName + "\", " + position + ")",
() => {
var spanInfo = this.languageService.getBreakpointStatementAtPosition(fileName, position);
return spanInfo;
});
}
/// SIGNATUREHELP
/// Computes a string representation of the signatures at the requested position
/// in the active file.
public getSignatureAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getSignatureAtPosition(\"" + fileName + "\", " + position + ")",
() => {
var signatureInfo = this.languageService.getSignatureAtPosition(fileName, position);
return signatureInfo;
});
}
/// GOTO DEFINITION
/// Computes the definition location and file for the symbol
/// at the requested position.
public getDefinitionAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getDefinitionAtPosition(\"" + fileName + "\", " + position + ")",
() => {
return this.languageService.getDefinitionAtPosition(fileName, position);
});
}
/// GET BRACE MATCHING
public getBraceMatchingAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getBraceMatchingAtPosition(\"" + fileName + "\", " + position + ")",
() => {
var textRanges = this.languageService.getBraceMatchingAtPosition(fileName, position);
return textRanges;
});
}
/// GET SMART INDENT
public getIndentationAtPosition(fileName: string, position: number, options: string /*Services.EditorOptions*/): string {
return this.forwardJSONCall(
"getIndentationAtPosition(\"" + fileName + "\", " + position + ")",
() => {
var localOptions: EditorOptions = JSON.parse(options);
var columnOffset = this.languageService.getIndentationAtPosition(fileName, position, localOptions);
return { value: columnOffset };
});
}
/// GET REFERENCES
/// Return references to a symbol at the requested position.
/// References are separated by "\n".
/// Each reference is a "fileindex min lim" sub-string.
public getReferencesAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getReferencesAtPosition(\"" + fileName + "\", " + position + ")",
() => {
return this.languageService.getReferencesAtPosition(fileName, position);
});
}
public getOccurrencesAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getOccurrencesAtPosition(\"" + fileName + "\", " + position + ")",
() => {
return this.languageService.getOccurrencesAtPosition(fileName, position);
});
}
/// GET IMPLEMENTORS
public getImplementorsAtPosition(fileName: string, position: number): string {
return this.forwardJSONCall(
"getImplementorsAtPosition(\"" + fileName + "\", " + position + ")",
() => {
return this.languageService.getImplementorsAtPosition(fileName, position);
});
}
/// COMPLETION LISTS
/// Get a string based representation of the completions
/// to provide at the given source position and providing a member completion
/// list if requested.
public getCompletionsAtPosition(fileName: string, position: number, isMemberCompletion: boolean) {
return this.forwardJSONCall(
"getCompletionsAtPosition(\"" + fileName + "\", " + position + ", " + isMemberCompletion + ")",
() => {
var completion = this.languageService.getCompletionsAtPosition(fileName, position, isMemberCompletion);
return completion;
});
}
/// Get a string based representation of a completion list entry details
public getCompletionEntryDetails(fileName: string, position: number, entryName: string) {
return this.forwardJSONCall(
"getCompletionEntryDetails(\"" + fileName + "\", " + position + ", " + entryName + ")",
() => {
var details = this.languageService.getCompletionEntryDetails(fileName, position, entryName);
return details;
});
}
/// FORMAT SELECTION
public getFormattingEditsForRange(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string {
return this.forwardJSONCall(
"getFormattingEditsForRange(\"" + fileName + "\", " + minChar + ", " + limChar + ")",
() => {
var localOptions: FormatCodeOptions = JSON.parse(options);
var edits = this.languageService.getFormattingEditsForRange(fileName, minChar, limChar, localOptions);
return edits;
});
}
/// FORMAT DOCUMENT
public getFormattingEditsForDocument(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string {
return this.forwardJSONCall(
"getFormattingEditsForDocument(\"" + fileName + "\", " + minChar + ", " + limChar + ")",
() => {
var localOptions: FormatCodeOptions = JSON.parse(options);
var edits = this.languageService.getFormattingEditsForDocument(fileName, minChar, limChar, localOptions);
return edits;
});
}
/// FORMAT ON PASTE
public getFormattingEditsOnPaste(fileName: string, minChar: number, limChar: number, options: string/*Services.FormatCodeOptions*/): string {
return this.forwardJSONCall(
"getFormattingEditsOnPaste(\"" + fileName + "\", " + minChar + ", " + limChar + ")",
() => {
var localOptions: FormatCodeOptions = JSON.parse(options);
var edits = this.languageService.getFormattingEditsOnPaste(fileName, minChar, limChar, localOptions);
return edits;
});
}
/// FORMAT
public getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: string/*Services.FormatCodeOptions*/): string {
return this.forwardJSONCall(
"getFormattingEditsAfterKeystroke(\"" + fileName + "\", " + position + ", \"" + key + "\")",
() => {
var localOptions: FormatCodeOptions = JSON.parse(options);
var edits = this.languageService.getFormattingEditsAfterKeystroke(fileName, position, key, localOptions);
return edits;
});
}
/// NAVIGATE TO
/// Return a list of symbols that are interesting to navigate to
public getNavigateToItems(searchValue: string): string {
return this.forwardJSONCall(
"getNavigateToItems(\"" + searchValue + "\")",
() => {
var items = this.languageService.getNavigateToItems(searchValue);
var result = this._navigateToItemsToString(items);
return result;
});
}
// GET SCRIPT LEXICAL STRUCTURE
//
public getScriptLexicalStructure(fileName: string): string {
return this.forwardJSONCall(
"getScriptLexicalStructure(\"" + fileName + "\")",
() => {
var items = this.languageService.getScriptLexicalStructure(fileName);
var result = this._navigateToItemsToString(items);
return result;
});
}
// GET OUTLINING REGIONS
//
public getOutliningRegions(fileName: string): string {
return this.forwardJSONCall(
"getOutliningRegions(\"" + fileName + "\")",
() => {
var items = this.languageService.getOutliningRegions(fileName);
return items;
});
}
/// Emit
public getEmitOutput(fileName: string): string {
return this.forwardJSONCall(
"getEmitOutput(\"" + fileName + "\")",
() => {
var output = this.languageService.getEmitOutput(fileName);
return output;
});
}
private _navigateToItemsToString(items: NavigateToItem[]): any {
var result: {
name: string;
kind: string;
kindModifiers: string;
containerName: string;
containerKind: string;
matchKind: string;
fileName: string;
minChar: number;
limChar: number;
additionalSpans?: { start: number; end: number; }[];
}[] = [];
for (var i = 0; i < items.length; i++) {
var item = items[i];
result.push({
name: item.name,
kind: item.kind,
kindModifiers: item.kindModifiers,
containerName: item.containerName,
containerKind: item.containerKind,
matchKind: item.matchKind,
fileName: item.fileName,
minChar: item.minChar,
limChar: item.limChar,
additionalSpans: item.additionalSpans ? item.additionalSpans.map(i => { return { start: i.minChar, end: i.limChar }; }) : undefined
});
}
return result;
}
}
class ClassifierShimObject extends ShimBase implements ClassifierShim {
public classifier: Classifier;
constructor(factory: ShimFactory, public host: Logger) {
super(factory);
this.classifier = createClassifier(this.host);
}
/// COLORIZATION
public getClassificationsForLine(text: string, lexState: EndOfLineState): string {
var classification = this.classifier.getClassificationsForLine(text, lexState);
var items = classification.entries;
var result = "";
for (var i = 0; i < items.length; i++) {
result += items[i].length + "\n";
result += items[i].classification + "\n";
}
result += classification.finalLexState;
return result;
}
}
class CoreServicesShimObject extends ShimBase implements CoreServicesShim {
constructor(factory: ShimFactory, public host: Logger) {
super(factory);
}
private forwardJSONCall(actionDescription: string, action: () => any): any {
return forwardJSONCall(this.host, actionDescription, action);
}
///
/// getPreProcessedFileInfo
///
public getPreProcessedFileInfo(fileName: string, sourceText: TypeScript.IScriptSnapshot): string {
return this.forwardJSONCall(
"getPreProcessedFileInfo(\"" + fileName + "\")",
() => {
var result = TypeScript.preProcessFile(fileName, sourceText);
return result;
});
}
///
/// getDefaultCompilationSettings
///
public getDefaultCompilationSettings(): string {
return this.forwardJSONCall(
"getDefaultCompilationSettings()",
() => {
return compilerOptionsToCompilationSettings(getDefaultCompilerOptions());
});
}
}
export class TypeScriptServicesFactory implements ShimFactory {
private _shims: Shim[] = [];
private documentRegistry: DocumentRegistry = createDocumentRegistry();
public createLanguageServiceShim(host: LanguageServiceShimHost): LanguageServiceShim {
try {
var hostAdapter = new LanguageServiceShimHostAdapter(host);
var pullLanguageService = createLanguageService(hostAdapter, this.documentRegistry);
return new LanguageServiceShimObject(this, host, pullLanguageService);
}
catch (err) {
logInternalError(host, err);
throw err;
}
}
public createClassifierShim(host: Logger): ClassifierShim {
try {
return new ClassifierShimObject(this, host);
}
catch (err) {
logInternalError(host, err);
throw err;
}
}
public createCoreServicesShim(host: Logger): CoreServicesShim {
try {
return new CoreServicesShimObject(this, host);
}
catch (err) {
logInternalError(host, err);
throw err;
}
}
public close(): void {
// Forget all the registered shims
this._shims = [];
this.documentRegistry = createDocumentRegistry();
}
public registerShim(shim: Shim): void {
this._shims.push(shim);
}
public unregisterShim(shim: Shim): void {
for (var i = 0, n = this._shims.length; i < n; i++) {
if (this._shims[i] === shim) {
delete this._shims[i];
return;
}
}
throw TypeScript.Errors.invalidOperation();
}
}
}
/// TODO: this is used by VS, clean this up on both sides of the interfrace
module TypeScript.Services {
export var TypeScriptServicesFactory = ts.TypeScriptServicesFactory;
}
+348
View File
@@ -0,0 +1,348 @@
// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0.
// See LICENSE.txt in the project root for complete license information.
///<reference path='references.ts' />
module TypeScript.Services {
export interface IPartiallyWrittenTypeArgumentListInformation {
genericIdentifer: TypeScript.ISyntaxToken;
lessThanToken: TypeScript.ISyntaxToken;
argumentIndex: number;
}
export interface IExpressionWithArgumentListSyntax extends IExpressionSyntax {
expression: IExpressionSyntax;
argumentList: ArgumentListSyntax;
}
export class SignatureInfoHelpers {
// A partially written generic type expression is not guaranteed to have the correct syntax tree. the expression could be parsed as less than/greater than expression or a comma expression
// or some other combination depending on what the user has typed so far. For the purposes of signature help we need to consider any location after "<" as a possible generic type reference.
// To do this, the method will back parse the expression starting at the position required. it will try to parse the current expression as a generic type expression, if it did succeed it
// will return the generic identifier that started the expression (e.g. "foo" in "foo<any, |"). It is then up to the caller to ensure that this is a valid generic expression through
// looking up the type. The method will also keep track of the parameter index inside the expression.
public static isInPartiallyWrittenTypeArgumentList(syntaxTree: TypeScript.SyntaxTree, position: number): IPartiallyWrittenTypeArgumentListInformation {
var token = Syntax.findTokenOnLeft(syntaxTree.sourceUnit(), position, /*includeSkippedTokens*/ true);
if (token && TypeScript.Syntax.hasAncestorOfKind(token, TypeScript.SyntaxKind.TypeParameterList)) {
// We are in the wrong generic list. bail out
return null;
}
var stack = 0;
var argumentIndex = 0;
whileLoop:
while (token) {
switch (token.kind()) {
case TypeScript.SyntaxKind.LessThanToken:
if (stack === 0) {
// Found the beginning of the generic argument expression
var lessThanToken = token;
token = previousToken(token, /*includeSkippedTokens*/ true);
if (!token || token.kind() !== TypeScript.SyntaxKind.IdentifierName) {
break whileLoop;
}
// Found the name, return the data
return {
genericIdentifer: token,
lessThanToken: lessThanToken,
argumentIndex: argumentIndex
};
}
else if (stack < 0) {
// Seen one too many less than tokens, bail out
break whileLoop;
}
else {
stack--;
}
break;
case TypeScript.SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
stack++;
// Intentaion fall through
case TypeScript.SyntaxKind.GreaterThanToken:
stack++;
break;
case TypeScript.SyntaxKind.CommaToken:
if (stack == 0) {
argumentIndex++;
}
break;
case TypeScript.SyntaxKind.CloseBraceToken:
// This can be object type, skip untill we find the matching open brace token
var unmatchedOpenBraceTokens = 0;
// Skip untill the matching open brace token
token = SignatureInfoHelpers.moveBackUpTillMatchingTokenKind(token, TypeScript.SyntaxKind.CloseBraceToken, TypeScript.SyntaxKind.OpenBraceToken);
if (!token) {
// No matching token was found. bail out
break whileLoop;
}
break;
case TypeScript.SyntaxKind.EqualsGreaterThanToken:
// This can be a function type or a constructor type. In either case, we want to skip the function defintion
token = previousToken(token, /*includeSkippedTokens*/ true);
if (token && token.kind() === TypeScript.SyntaxKind.CloseParenToken) {
// Skip untill the matching open paren token
token = SignatureInfoHelpers.moveBackUpTillMatchingTokenKind(token, TypeScript.SyntaxKind.CloseParenToken, TypeScript.SyntaxKind.OpenParenToken);
if (token && token.kind() === TypeScript.SyntaxKind.GreaterThanToken) {
// Another generic type argument list, skip it\
token = SignatureInfoHelpers.moveBackUpTillMatchingTokenKind(token, TypeScript.SyntaxKind.GreaterThanToken, TypeScript.SyntaxKind.LessThanToken);
}
if (token && token.kind() === TypeScript.SyntaxKind.NewKeyword) {
// In case this was a constructor type, skip the new keyword
token = previousToken(token, /*includeSkippedTokens*/ true);
}
if (!token) {
// No matching token was found. bail out
break whileLoop;
}
}
else {
// This is not a funtion type. exit the main loop
break whileLoop;
}
break;
case TypeScript.SyntaxKind.IdentifierName:
case TypeScript.SyntaxKind.AnyKeyword:
case TypeScript.SyntaxKind.NumberKeyword:
case TypeScript.SyntaxKind.StringKeyword:
case TypeScript.SyntaxKind.VoidKeyword:
case TypeScript.SyntaxKind.BooleanKeyword:
case TypeScript.SyntaxKind.DotToken:
case TypeScript.SyntaxKind.OpenBracketToken:
case TypeScript.SyntaxKind.CloseBracketToken:
// Valid tokens in a type name. Skip.
break;
default:
break whileLoop;
}
token = previousToken(token, /*includeSkippedTokens*/ true);
}
return null;
}
public static getSignatureInfoFromSignatureSymbol(symbol: TypeScript.PullSymbol, signatures: TypeScript.PullSignatureSymbol[], enclosingScopeSymbol: TypeScript.PullSymbol, compilerState: LanguageServiceCompiler) {
var signatureGroup: FormalSignatureItemInfo[] = [];
var hasOverloads = signatures.length > 1;
for (var i = 0, n = signatures.length; i < n; i++) {
var signature = signatures[i];
// filter out the definition signature if there are overloads
if (hasOverloads && signature.isDefinition()) {
continue;
}
var signatureGroupInfo = new FormalSignatureItemInfo();
var paramIndexInfo: number[] = [];
var functionName = signature.getScopedNameEx(enclosingScopeSymbol).toString();
if (!functionName && (!symbol.isType() || (<TypeScript.PullTypeSymbol>symbol).isNamedTypeSymbol())) {
functionName = symbol.getScopedNameEx(enclosingScopeSymbol).toString();
}
var signatureMemberName = signature.getSignatureTypeNameEx(functionName, /*shortform*/ false, /*brackets*/ false, enclosingScopeSymbol, /*getParamMarkerInfo*/ true, /*getTypeParameterMarkerInfo*/ true);
signatureGroupInfo.signatureInfo = TypeScript.MemberName.memberNameToString(signatureMemberName, paramIndexInfo);
signatureGroupInfo.docComment = signature.docComments();
var parameterMarkerIndex = 0;
if (signature.isGeneric()) {
var typeParameters = signature.getTypeParameters();
for (var j = 0, m = typeParameters.length; j < m; j++) {
var typeParameter = typeParameters[j];
var signatureTypeParameterInfo = new FormalTypeParameterInfo();
signatureTypeParameterInfo.name = typeParameter.getDisplayName();
signatureTypeParameterInfo.docComment = typeParameter.docComments();
signatureTypeParameterInfo.minChar = paramIndexInfo[2 * parameterMarkerIndex];
signatureTypeParameterInfo.limChar = paramIndexInfo[2 * parameterMarkerIndex + 1];
parameterMarkerIndex++;
signatureGroupInfo.typeParameters.push(signatureTypeParameterInfo);
}
}
var parameters = signature.parameters;
for (var j = 0, m = parameters.length; j < m; j++) {
var parameter = parameters[j];
var signatureParameterInfo = new FormalParameterInfo();
signatureParameterInfo.isVariable = signature.hasVarArgs && (j === parameters.length - 1);
signatureParameterInfo.name = parameter.getDisplayName();
signatureParameterInfo.docComment = parameter.docComments();
signatureParameterInfo.minChar = paramIndexInfo[2 * parameterMarkerIndex];
signatureParameterInfo.limChar = paramIndexInfo[2 * parameterMarkerIndex + 1];
parameterMarkerIndex++;
signatureGroupInfo.parameters.push(signatureParameterInfo);
}
signatureGroup.push(signatureGroupInfo);
}
return signatureGroup;
}
public static getSignatureInfoFromGenericSymbol(symbol: TypeScript.PullSymbol, enclosingScopeSymbol: TypeScript.PullSymbol, compilerState: LanguageServiceCompiler) {
var signatureGroupInfo = new FormalSignatureItemInfo();
var paramIndexInfo: number[] = [];
var symbolName = symbol.getScopedNameEx(enclosingScopeSymbol, /*skipTypeParametersInName*/ false, /*useConstaintInName*/ true, /*getPrettyTypeName*/ false, /*getTypeParamMarkerInfo*/ true);
signatureGroupInfo.signatureInfo = TypeScript.MemberName.memberNameToString(symbolName, paramIndexInfo);
signatureGroupInfo.docComment = symbol.docComments();
var parameterMarkerIndex = 0;
var typeSymbol = symbol.type;
var typeParameters = typeSymbol.getTypeParameters();
for (var i = 0, n = typeParameters.length; i < n; i++) {
var typeParameter = typeParameters[i];
var signatureTypeParameterInfo = new FormalTypeParameterInfo();
signatureTypeParameterInfo.name = typeParameter.getDisplayName();
signatureTypeParameterInfo.docComment = typeParameter.docComments();
signatureTypeParameterInfo.minChar = paramIndexInfo[2 * i];
signatureTypeParameterInfo.limChar = paramIndexInfo[2 * i + 1];
signatureGroupInfo.typeParameters.push(signatureTypeParameterInfo);
}
return [signatureGroupInfo];
}
public static getActualSignatureInfoFromCallExpression(ast: IExpressionWithArgumentListSyntax, caretPosition: number, typeParameterInformation: IPartiallyWrittenTypeArgumentListInformation): ActualSignatureInfo {
if (!ast) {
return null;
}
var result = new ActualSignatureInfo();
// The expression is not guaranteed to be complete, we need to populate the min and lim with the most accurate information we have about
// type argument and argument lists
var parameterMinChar = caretPosition;
var parameterLimChar = caretPosition;
if (ast.argumentList.typeArgumentList) {
parameterMinChar = Math.min(start(ast.argumentList.typeArgumentList));
parameterLimChar = Math.max(Math.max(start(ast.argumentList.typeArgumentList), end(ast.argumentList.typeArgumentList) + trailingTriviaWidth(ast.argumentList.typeArgumentList)));
}
if (ast.argumentList.arguments) {
parameterMinChar = Math.min(parameterMinChar, end(ast.argumentList.openParenToken));
parameterLimChar = Math.max(parameterLimChar,
ast.argumentList.closeParenToken.fullWidth() > 0 ? start(ast.argumentList.closeParenToken) : fullEnd(ast.argumentList));
}
result.parameterMinChar = parameterMinChar;
result.parameterLimChar = parameterLimChar;
result.currentParameterIsTypeParameter = false;
result.currentParameter = -1;
if (typeParameterInformation) {
result.currentParameterIsTypeParameter = true;
result.currentParameter = typeParameterInformation.argumentIndex;
}
else if (ast.argumentList.arguments && ast.argumentList.arguments.length > 0) {
result.currentParameter = 0;
for (var index = 0; index < ast.argumentList.arguments.length; index++) {
if (caretPosition > end(ast.argumentList.arguments[index]) + lastToken(ast.argumentList.arguments[index]).trailingTriviaWidth()) {
result.currentParameter++;
}
}
}
return result;
}
public static getActualSignatureInfoFromPartiallyWritenGenericExpression(caretPosition: number, typeParameterInformation: IPartiallyWrittenTypeArgumentListInformation): ActualSignatureInfo {
var result = new ActualSignatureInfo();
result.parameterMinChar = start(typeParameterInformation.lessThanToken);
result.parameterLimChar = Math.max(fullEnd(typeParameterInformation.lessThanToken), caretPosition);
result.currentParameterIsTypeParameter = true;
result.currentParameter = typeParameterInformation.argumentIndex;
return result;
}
public static isSignatureHelpBlocker(sourceUnit: TypeScript.SourceUnitSyntax, position: number): boolean {
// We shouldn't be getting a possition that is outside the file because
// isEntirelyInsideComment can't handle when the position is out of bounds,
// callers should be fixed, however we should be resiliant to bad inputs
// so we return true (this position is a blocker for getting signature help)
if (position < 0 || position > fullWidth(sourceUnit)) {
return true;
}
return TypeScript.Syntax.isEntirelyInsideComment(sourceUnit, position);
}
public static isTargetOfObjectCreationExpression(positionedToken: TypeScript.ISyntaxToken): boolean {
var positionedParent = TypeScript.Syntax.getAncestorOfKind(positionedToken, TypeScript.SyntaxKind.ObjectCreationExpression);
if (positionedParent) {
var objectCreationExpression = <TypeScript.ObjectCreationExpressionSyntax> positionedParent;
var expressionRelativeStart = objectCreationExpression.newKeyword.fullWidth();
var tokenRelativeStart = positionedToken.fullStart() - fullStart(positionedParent);
return tokenRelativeStart >= expressionRelativeStart &&
tokenRelativeStart <= (expressionRelativeStart + fullWidth(objectCreationExpression.expression));
}
return false;
}
private static moveBackUpTillMatchingTokenKind(token: TypeScript.ISyntaxToken, tokenKind: TypeScript.SyntaxKind, matchingTokenKind: TypeScript.SyntaxKind): TypeScript.ISyntaxToken {
if (!token || token.kind() !== tokenKind) {
throw TypeScript.Errors.invalidOperation();
}
// Skip the current token
token = previousToken(token, /*includeSkippedTokens*/ true);
var stack = 0;
while (token) {
if (token.kind() === matchingTokenKind) {
if (stack === 0) {
// Found the matching token, return
return token;
}
else if (stack < 0) {
// tokens overlapped.. bail out.
break;
}
else {
stack--;
}
}
else if (token.kind() === tokenKind) {
stack++;
}
// Move back
token = previousToken(token, /*includeSkippedTokens*/ true);
}
// Did not find matching token
return null;
}
}
}
File diff suppressed because it is too large Load Diff
+70
View File
@@ -0,0 +1,70 @@
///<reference path='references.ts' />
module TypeScript {
export module CharacterInfo {
export function isDecimalDigit(c: number): boolean {
return c >= CharacterCodes._0 && c <= CharacterCodes._9;
}
export function isOctalDigit(c: number): boolean {
return c >= CharacterCodes._0 && c <= CharacterCodes._7;
}
export function isHexDigit(c: number): boolean {
return CharacterInfo.isDecimalDigit(c) ||
(c >= CharacterCodes.A && c <= CharacterCodes.F) ||
(c >= CharacterCodes.a && c <= CharacterCodes.f);
}
export function hexValue(c: number): number {
// Debug.assert(isHexDigit(c));
return CharacterInfo.isDecimalDigit(c)
? (c - CharacterCodes._0)
: (c >= CharacterCodes.A && c <= CharacterCodes.F)
? c - CharacterCodes.A + 10
: c - CharacterCodes.a + 10;
}
export function isWhitespace(ch: number): boolean {
switch (ch) {
// Unicode 3.0 space characters.
case CharacterCodes.space:
case CharacterCodes.nonBreakingSpace:
case CharacterCodes.enQuad:
case CharacterCodes.emQuad:
case CharacterCodes.enSpace:
case CharacterCodes.emSpace:
case CharacterCodes.threePerEmSpace:
case CharacterCodes.fourPerEmSpace:
case CharacterCodes.sixPerEmSpace:
case CharacterCodes.figureSpace:
case CharacterCodes.punctuationSpace:
case CharacterCodes.thinSpace:
case CharacterCodes.hairSpace:
case CharacterCodes.zeroWidthSpace:
case CharacterCodes.narrowNoBreakSpace:
case CharacterCodes.ideographicSpace:
case CharacterCodes.tab:
case CharacterCodes.verticalTab:
case CharacterCodes.formFeed:
case CharacterCodes.byteOrderMark:
return true;
}
return false;
}
export function isLineTerminator(ch: number): boolean {
switch (ch) {
case CharacterCodes.carriageReturn:
case CharacterCodes.lineFeed:
case CharacterCodes.paragraphSeparator:
case CharacterCodes.lineSeparator:
return true;
}
return false;
}
}
}
+26
View File
@@ -0,0 +1,26 @@
///<reference path='references.ts' />
module TypeScript {
export enum SyntaxConstants {
None = 0,
// Masks that we use to place information about a node into a single int. The first bit tells
// us if we've computed the data for a node.
//
// The second bit tells us if the node is incrementally reusable if it does not
// containe any skipped tokens, zero width tokens, regex tokens in it ("/", "/=" or "/.../"),
// and contains no tokens that were parser generated.
//
// The next bit lets us know if the nodes was parsed in a strict context or node. A node can
// only be used by the incremental parser if it is parsed in the same strict context as before.
// last masks off the part of the int
//
// The width of the node is stored in the remainder of the int. This allows us up to 512MB
// for a node by using all 29 bits. However, in the common case, we'll use less than 29 bits
// for the width. Thus, the info will be stored in a single int in chakra.
NodeDataComputed = 0x00000001, // 0000 0000 0000 0000 0000 0000 0000 0001
NodeIncrementallyUnusableMask = 0x00000002, // 0000 0000 0000 0000 0000 0000 0000 0010
NodeParsedInStrictModeMask = 0x00000004, // 0000 0000 0000 0000 0000 0000 0000 0100
NodeFullWidthShift = 3, // 1111 1111 1111 1111 1111 1111 1111 1000
}
}
@@ -0,0 +1,353 @@
///<reference path='references.ts' />
module TypeScript {
export class SyntaxVisitor implements ISyntaxVisitor {
public defaultVisit(node: ISyntaxNodeOrToken): any {
return null;
}
public visitToken(token: ISyntaxToken): any {
return this.defaultVisit(token);
}
public visitSourceUnit(node: SourceUnitSyntax): any {
return this.defaultVisit(node);
}
public visitQualifiedName(node: QualifiedNameSyntax): any {
return this.defaultVisit(node);
}
public visitObjectType(node: ObjectTypeSyntax): any {
return this.defaultVisit(node);
}
public visitFunctionType(node: FunctionTypeSyntax): any {
return this.defaultVisit(node);
}
public visitArrayType(node: ArrayTypeSyntax): any {
return this.defaultVisit(node);
}
public visitConstructorType(node: ConstructorTypeSyntax): any {
return this.defaultVisit(node);
}
public visitGenericType(node: GenericTypeSyntax): any {
return this.defaultVisit(node);
}
public visitTypeQuery(node: TypeQuerySyntax): any {
return this.defaultVisit(node);
}
public visitInterfaceDeclaration(node: InterfaceDeclarationSyntax): any {
return this.defaultVisit(node);
}
public visitFunctionDeclaration(node: FunctionDeclarationSyntax): any {
return this.defaultVisit(node);
}
public visitModuleDeclaration(node: ModuleDeclarationSyntax): any {
return this.defaultVisit(node);
}
public visitClassDeclaration(node: ClassDeclarationSyntax): any {
return this.defaultVisit(node);
}
public visitEnumDeclaration(node: EnumDeclarationSyntax): any {
return this.defaultVisit(node);
}
public visitImportDeclaration(node: ImportDeclarationSyntax): any {
return this.defaultVisit(node);
}
public visitExportAssignment(node: ExportAssignmentSyntax): any {
return this.defaultVisit(node);
}
public visitMemberFunctionDeclaration(node: MemberFunctionDeclarationSyntax): any {
return this.defaultVisit(node);
}
public visitMemberVariableDeclaration(node: MemberVariableDeclarationSyntax): any {
return this.defaultVisit(node);
}
public visitConstructorDeclaration(node: ConstructorDeclarationSyntax): any {
return this.defaultVisit(node);
}
public visitIndexMemberDeclaration(node: IndexMemberDeclarationSyntax): any {
return this.defaultVisit(node);
}
public visitGetAccessor(node: GetAccessorSyntax): any {
return this.defaultVisit(node);
}
public visitSetAccessor(node: SetAccessorSyntax): any {
return this.defaultVisit(node);
}
public visitPropertySignature(node: PropertySignatureSyntax): any {
return this.defaultVisit(node);
}
public visitCallSignature(node: CallSignatureSyntax): any {
return this.defaultVisit(node);
}
public visitConstructSignature(node: ConstructSignatureSyntax): any {
return this.defaultVisit(node);
}
public visitIndexSignature(node: IndexSignatureSyntax): any {
return this.defaultVisit(node);
}
public visitMethodSignature(node: MethodSignatureSyntax): any {
return this.defaultVisit(node);
}
public visitBlock(node: BlockSyntax): any {
return this.defaultVisit(node);
}
public visitIfStatement(node: IfStatementSyntax): any {
return this.defaultVisit(node);
}
public visitVariableStatement(node: VariableStatementSyntax): any {
return this.defaultVisit(node);
}
public visitExpressionStatement(node: ExpressionStatementSyntax): any {
return this.defaultVisit(node);
}
public visitReturnStatement(node: ReturnStatementSyntax): any {
return this.defaultVisit(node);
}
public visitSwitchStatement(node: SwitchStatementSyntax): any {
return this.defaultVisit(node);
}
public visitBreakStatement(node: BreakStatementSyntax): any {
return this.defaultVisit(node);
}
public visitContinueStatement(node: ContinueStatementSyntax): any {
return this.defaultVisit(node);
}
public visitForStatement(node: ForStatementSyntax): any {
return this.defaultVisit(node);
}
public visitForInStatement(node: ForInStatementSyntax): any {
return this.defaultVisit(node);
}
public visitEmptyStatement(node: EmptyStatementSyntax): any {
return this.defaultVisit(node);
}
public visitThrowStatement(node: ThrowStatementSyntax): any {
return this.defaultVisit(node);
}
public visitWhileStatement(node: WhileStatementSyntax): any {
return this.defaultVisit(node);
}
public visitTryStatement(node: TryStatementSyntax): any {
return this.defaultVisit(node);
}
public visitLabeledStatement(node: LabeledStatementSyntax): any {
return this.defaultVisit(node);
}
public visitDoStatement(node: DoStatementSyntax): any {
return this.defaultVisit(node);
}
public visitDebuggerStatement(node: DebuggerStatementSyntax): any {
return this.defaultVisit(node);
}
public visitWithStatement(node: WithStatementSyntax): any {
return this.defaultVisit(node);
}
public visitPrefixUnaryExpression(node: PrefixUnaryExpressionSyntax): any {
return this.defaultVisit(node);
}
public visitDeleteExpression(node: DeleteExpressionSyntax): any {
return this.defaultVisit(node);
}
public visitTypeOfExpression(node: TypeOfExpressionSyntax): any {
return this.defaultVisit(node);
}
public visitVoidExpression(node: VoidExpressionSyntax): any {
return this.defaultVisit(node);
}
public visitConditionalExpression(node: ConditionalExpressionSyntax): any {
return this.defaultVisit(node);
}
public visitBinaryExpression(node: BinaryExpressionSyntax): any {
return this.defaultVisit(node);
}
public visitPostfixUnaryExpression(node: PostfixUnaryExpressionSyntax): any {
return this.defaultVisit(node);
}
public visitMemberAccessExpression(node: MemberAccessExpressionSyntax): any {
return this.defaultVisit(node);
}
public visitInvocationExpression(node: InvocationExpressionSyntax): any {
return this.defaultVisit(node);
}
public visitArrayLiteralExpression(node: ArrayLiteralExpressionSyntax): any {
return this.defaultVisit(node);
}
public visitObjectLiteralExpression(node: ObjectLiteralExpressionSyntax): any {
return this.defaultVisit(node);
}
public visitObjectCreationExpression(node: ObjectCreationExpressionSyntax): any {
return this.defaultVisit(node);
}
public visitParenthesizedExpression(node: ParenthesizedExpressionSyntax): any {
return this.defaultVisit(node);
}
public visitParenthesizedArrowFunctionExpression(node: ParenthesizedArrowFunctionExpressionSyntax): any {
return this.defaultVisit(node);
}
public visitSimpleArrowFunctionExpression(node: SimpleArrowFunctionExpressionSyntax): any {
return this.defaultVisit(node);
}
public visitCastExpression(node: CastExpressionSyntax): any {
return this.defaultVisit(node);
}
public visitElementAccessExpression(node: ElementAccessExpressionSyntax): any {
return this.defaultVisit(node);
}
public visitFunctionExpression(node: FunctionExpressionSyntax): any {
return this.defaultVisit(node);
}
public visitOmittedExpression(node: OmittedExpressionSyntax): any {
return this.defaultVisit(node);
}
public visitVariableDeclaration(node: VariableDeclarationSyntax): any {
return this.defaultVisit(node);
}
public visitVariableDeclarator(node: VariableDeclaratorSyntax): any {
return this.defaultVisit(node);
}
public visitArgumentList(node: ArgumentListSyntax): any {
return this.defaultVisit(node);
}
public visitParameterList(node: ParameterListSyntax): any {
return this.defaultVisit(node);
}
public visitTypeArgumentList(node: TypeArgumentListSyntax): any {
return this.defaultVisit(node);
}
public visitTypeParameterList(node: TypeParameterListSyntax): any {
return this.defaultVisit(node);
}
public visitHeritageClause(node: HeritageClauseSyntax): any {
return this.defaultVisit(node);
}
public visitEqualsValueClause(node: EqualsValueClauseSyntax): any {
return this.defaultVisit(node);
}
public visitCaseSwitchClause(node: CaseSwitchClauseSyntax): any {
return this.defaultVisit(node);
}
public visitDefaultSwitchClause(node: DefaultSwitchClauseSyntax): any {
return this.defaultVisit(node);
}
public visitElseClause(node: ElseClauseSyntax): any {
return this.defaultVisit(node);
}
public visitCatchClause(node: CatchClauseSyntax): any {
return this.defaultVisit(node);
}
public visitFinallyClause(node: FinallyClauseSyntax): any {
return this.defaultVisit(node);
}
public visitTypeParameter(node: TypeParameterSyntax): any {
return this.defaultVisit(node);
}
public visitConstraint(node: ConstraintSyntax): any {
return this.defaultVisit(node);
}
public visitSimplePropertyAssignment(node: SimplePropertyAssignmentSyntax): any {
return this.defaultVisit(node);
}
public visitFunctionPropertyAssignment(node: FunctionPropertyAssignmentSyntax): any {
return this.defaultVisit(node);
}
public visitParameter(node: ParameterSyntax): any {
return this.defaultVisit(node);
}
public visitEnumElement(node: EnumElementSyntax): any {
return this.defaultVisit(node);
}
public visitTypeAnnotation(node: TypeAnnotationSyntax): any {
return this.defaultVisit(node);
}
public visitExternalModuleReference(node: ExternalModuleReferenceSyntax): any {
return this.defaultVisit(node);
}
public visitModuleNameModuleReference(node: ModuleNameModuleReferenceSyntax): any {
return this.defaultVisit(node);
}
}
}
+21
View File
@@ -0,0 +1,21 @@
///<reference path='references.ts' />
module TypeScript {
export class DepthLimitedWalker extends SyntaxWalker {
private _depth: number = 0;
private _maximumDepth: number = 0;
constructor(maximumDepth: number) {
super();
this._maximumDepth = maximumDepth;
}
public visitNode(node: ISyntaxNode): void {
if (this._depth < this._maximumDepth) {
this._depth++;
super.visitNode(node);
this._depth--;
}
}
}
}
File diff suppressed because it is too large Load Diff
+13
View File
@@ -0,0 +1,13 @@
///<reference path='references.ts' />
module TypeScript {
export class FormattingOptions {
constructor(public useTabs: boolean,
public spacesPerTab: number,
public indentSpaces: number,
public newLineCharacter: string) {
}
public static defaultOptions = new FormattingOptions(/*useTabs:*/ false, /*spacesPerTab:*/ 4, /*indentSpaces:*/ 4, /*newLineCharacter*/ "\r\n");
}
}
+865
View File
@@ -0,0 +1,865 @@
///<reference path="references.ts" />
module TypeScript.IncrementalParser {
interface IParserRewindPoint {
// Information used by the incremental parser source.
oldSourceUnitCursor: SyntaxCursor;
changeDelta: number;
changeRange: TextChangeRange;
}
// Parser source used in incremental scenarios. This parser source wraps an old tree, text
// change and new text, and uses all three to provide nodes and tokens to the parser. In
// general, nodes from the old tree are returned as long as they do not intersect with the text
// change. Then, once the text change is reached, tokens from the old tree are returned as
// long as they do not intersect with the text change. Then, the text that is actually changed
// will be scanned using a normal scanner. Then, once the new text is scanned, the source will
// attempt to sync back up with nodes or tokens that started where the new tokens end. Once it
// can do that, then all subsequent data will come from the original tree.
//
// This allows for an enormous amount of tree reuse in common scenarios. Situations that
// prevent this level of reuse include substantially destructive operations like introducing
// "/*" without a "*/" nearby to terminate the comment.
function createParserSource(oldSyntaxTree: SyntaxTree, textChangeRange: TextChangeRange, text: ISimpleText): Parser.IParserSource {
var fileName = oldSyntaxTree.fileName();
var languageVersion = oldSyntaxTree.languageVersion();
// The underlying source that we will use to scan tokens from any new text, or any tokens
// from the old tree that we decide we can't use for any reason. We will also continue
// scanning tokens from this source until we've decided that we're resynchronized and can
// read in subsequent data from the old tree.
//
// This parser source also keeps track of the absolute position in the text that we're in,
// and any token diagnostics produced. That way we dont' have to track that ourselves.
var _scannerParserSource: Scanner.IScannerParserSource;
// The range of text in the *original* text that was changed, and the new length of it after
// the change.
var _changeRange: TextChangeRange;
// Cached value of _changeRange.newSpan(). Cached for performance.
var _changeRangeNewSpan: TextSpan;
// This number represents how our position in the old tree relates to the position we're
// pointing at in the new text. If it is 0 then our positions are in sync and we can read
// nodes or tokens from the old tree. If it is non-zero, then our positions are not in
// sync and we cannot use nodes or tokens from the old tree.
//
// Now, changeDelta could be negative or positive. Negative means 'the position we're at
// in the original tree is behind the position we're at in the text'. In this case we
// keep throwing out old nodes or tokens (and thus move forward in the original tree) until
// changeDelta becomes 0 again or positive. If it becomes 0 then we are resynched and can
// read nodes or tokesn from the tree.
//
// If changeDelta is positive, that means the current node or token we're pointing at in
// the old tree is at a further ahead position than the position we're pointing at in the
// new text. In this case we have no choice but to scan tokens from teh new text. We will
// continue to do so until, again, changeDelta becomes 0 and we've resynced, or change delta
// becomes negative and we need to skip nodes or tokes in the original tree.
var _changeDelta: number = 0;
// The cursor we use to navigate through and retrieve nodes and tokens from the old tree.
var _oldSourceUnitCursor = getSyntaxCursor();
var oldSourceUnit = oldSyntaxTree.sourceUnit();
var _outstandingRewindPointCount = 0;
// Start the cursor pointing at the first element in the source unit (if it exists).
if (oldSourceUnit.moduleElements.length > 0) {
_oldSourceUnitCursor.pushElement(childAt(oldSourceUnit.moduleElements, 0), /*indexInParent:*/ 0);
}
// In general supporting multiple individual edits is just not that important. So we
// just collapse this all down to a single range to make the code here easier. The only
// time this could be problematic would be if the user made a ton of discontinuous edits.
// For example, doing a column select on a *large* section of a code. If this is a
// problem, we can always update this code to handle multiple changes.
_changeRange = extendToAffectedRange(textChangeRange, oldSourceUnit);
_changeRangeNewSpan = _changeRange.newSpan();
// The old tree's length, plus whatever length change was caused by the edit
// Had better equal the new text's length!
if (Debug.shouldAssert(AssertionLevel.Aggressive)) {
Debug.assert((fullWidth(oldSourceUnit) - _changeRange.span().length() + _changeRange.newLength()) === text.length());
}
// Set up a scanner so that we can scan tokens out of the new text.
_scannerParserSource = Scanner.createParserSource(oldSyntaxTree.fileName(), text, oldSyntaxTree.languageVersion());
function release() {
_scannerParserSource.release();
_scannerParserSource = null;
_oldSourceUnitCursor = null;
_outstandingRewindPointCount = 0;
}
function extendToAffectedRange(changeRange: TextChangeRange,
sourceUnit: SourceUnitSyntax): TextChangeRange {
// Consider the following code:
// void foo() { /; }
//
// If the text changes with an insertion of / just before the semicolon then we end up with:
// void foo() { //; }
//
// If we were to just use the changeRange a is, then we would not rescan the { token
// (as it does not intersect the actual original change range). Because an edit may
// change the token touching it, we actually need to look back *at least* one token so
// that the prior token sees that change.
//
// Note: i believe (outside of regex tokens) max lookahead is just one token for
// TypeScript. However, if this turns out to be wrong, we may have to increase how much
// futher we look back.
//
// Note: lookahead handling for regex characters is handled specially in during
// incremental parsing, and does not need to be handled here.
var maxLookahead = 1;
var start = changeRange.span().start();
// the first iteration aligns us with the change start. subsequent iteration move us to
// the left by maxLookahead tokens. We only need to do this as long as we're not at the
// start of the tree.
for (var i = 0; start > 0 && i <= maxLookahead; i++) {
var token = findToken(sourceUnit, start);
// Debug.assert(token.kind !== SyntaxKind.None);
// Debug.assert(token.kind() === SyntaxKind.EndOfFileToken || token.fullWidth() > 0);
var position = token.fullStart();
start = Math.max(0, position - 1);
}
var finalSpan = TextSpan.fromBounds(start, changeRange.span().end());
var finalLength = changeRange.newLength() + (changeRange.span().start() - start);
return new TextChangeRange(finalSpan, finalLength);
}
function absolutePosition() {
return _scannerParserSource.absolutePosition();
}
function tokenDiagnostics(): Diagnostic[] {
return _scannerParserSource.tokenDiagnostics();
}
function getRewindPoint() {
// Get a rewind point for our new text reader and for our old source unit cursor.
var rewindPoint = <IParserRewindPoint>_scannerParserSource.getRewindPoint();
// Clone our cursor. That way we can restore to that point if hte parser needs to rewind.
var oldSourceUnitCursorClone = cloneSyntaxCursor(_oldSourceUnitCursor);
// Store where we were when the rewind point was created.
rewindPoint.changeDelta = _changeDelta;
rewindPoint.changeRange = _changeRange;
rewindPoint.oldSourceUnitCursor = _oldSourceUnitCursor;
_oldSourceUnitCursor = oldSourceUnitCursorClone;
// Debug.assert(rewindPoint.pinCount === _oldSourceUnitCursor.pinCount());
_outstandingRewindPointCount++;
return rewindPoint;
}
function rewind(rewindPoint: IParserRewindPoint): void {
// Restore our state to the values when the rewind point was created.
_changeRange = rewindPoint.changeRange;
_changeDelta = rewindPoint.changeDelta;
// Reset the cursor to what it was when we got the rewind point. Make sure to return
// our existing cursor to the pool so it can be reused.
returnSyntaxCursor(_oldSourceUnitCursor);
_oldSourceUnitCursor = rewindPoint.oldSourceUnitCursor;
// Null out the cursor that the rewind point points to. This way we don't try
// to return it in 'releaseRewindPoint'.
rewindPoint.oldSourceUnitCursor = null;
_scannerParserSource.rewind(rewindPoint);
}
function releaseRewindPoint(rewindPoint: IParserRewindPoint): void {
if (rewindPoint.oldSourceUnitCursor !== null) {
returnSyntaxCursor(rewindPoint.oldSourceUnitCursor);
}
_scannerParserSource.releaseRewindPoint(rewindPoint);
_outstandingRewindPointCount--;
Debug.assert(_outstandingRewindPointCount >= 0);
}
function isPinned() {
return _outstandingRewindPointCount > 0;
}
function canReadFromOldSourceUnit() {
// If we're currently pinned, then do not want to touch the cursor. Here's why. First,
// recall that we're 'pinned' when we're speculatively parsing. So say we were to allow
// returning old nodes/tokens while speculatively parsing. Then, the parser might start
// mutating the nodes and tokens we returned (i.e. by setting their parents). Then,
// when we rewound, those nodes and tokens would still have those updated parents.
// Parents which we just decided we did *not* want to parse (hence why we rewound). For
// Example, say we have something like:
//
// var v = f<a,b,c>e; // note: this is not generic.
//
// When incrementally parsing, we will need to speculatively parse to determine if the
// above is generic. This will cause us to reuse the "a, b, c" tokens, and set their
// parent to a new type argument list. A type argument list we will then throw away once
// we decide that it isn't actually generic. We will have now 'broken' the original tree.
//
// As such, the rule is simple. We only return nodes/tokens from teh original tree if
// we know the parser will accept and consume them and never rewind back before them.
if (isPinned()) {
return false;
}
// If our current absolute position is in the middle of the changed range in the new text
// then we definitely can't read from the old source unit right now.
if (_changeRange !== null && _changeRangeNewSpan.intersectsWithPosition(absolutePosition())) {
return false;
}
// First, try to sync up with the new text if we're behind.
syncCursorToNewTextIfBehind();
// Now, if we're synced up *and* we're not currently pinned in the new text scanner,
// then we can read a node from the cursor. If we're pinned in the scanner then we
// can't read a node from the cursor because we will mess up the pinned scanner when
// we try to move it forward past this node.
return _changeDelta === 0 &&
!_oldSourceUnitCursor.isFinished();
}
function updateTokens(nodeOrToken: ISyntaxNodeOrToken): void {
// If we got a node or token, and we're past the range of edited text, then walk its
// constituent tokens, making sure all their positions are correct. We don't need to
// do this for the tokens before the edited range (since their positions couldn't have
// been affected by the edit), and we don't need to do this for the tokens in the
// edited range, as their positions will be correct when the underlying parser source
// creates them.
var position = absolutePosition();
var tokenWasMoved = isPastChangeRange() && fullStart(nodeOrToken) !== position;
if (tokenWasMoved) {
setTokenFullStartWalker.position = position;
visitNodeOrToken(setTokenFullStartWalker, nodeOrToken);
}
}
function currentNode(): ISyntaxNode {
if (canReadFromOldSourceUnit()) {
// Try to read a node. If we can't then our caller will call back in and just try
// to get a token.
var node = tryGetNodeFromOldSourceUnit();
if (node !== null) {
// Make sure the positions for the tokens in this node are correct.
updateTokens(node);
return node;
}
}
// Either we were ahead of the old text, or we were pinned. No node can be read here.
return null;
}
function currentToken(): ISyntaxToken {
if (canReadFromOldSourceUnit()) {
var token = tryGetTokenFromOldSourceUnit();
if (token !== null) {
// Make sure the token's position/text is correct.
updateTokens(token);
return token;
}
}
// Either we couldn't read from the old source unit, or we weren't able to successfully
// get a token from it. In this case we need to read a token from the underlying text.
return _scannerParserSource.currentToken();
}
function currentContextualToken(): ISyntaxToken {
// Just delegate to the underlying source to handle
return _scannerParserSource.currentContextualToken();
}
function syncCursorToNewTextIfBehind() {
while (true) {
if (_oldSourceUnitCursor.isFinished()) {
// Can't sync up if the cursor is finished.
break;
}
if (_changeDelta >= 0) {
// Nothing to do if we're synced up or ahead of the text.
break;
}
// We're behind in the original tree. Throw out a node or token in an attempt to
// catch up to the position we're at in the new text.
var currentNodeOrToken = _oldSourceUnitCursor.currentNodeOrToken();
// If we're pointing at a node, and that node's width is less than our delta,
// then we can just skip that node. Otherwise, if we're pointing at a node
// whose width is greater than the delta, then crumble it and try again.
// Otherwise, we must be pointing at a token. Just skip it and try again.
if (isNode(currentNodeOrToken) && (fullWidth(currentNodeOrToken) > Math.abs(_changeDelta))) {
// We were pointing at a node whose width was more than changeDelta. Crumble the
// node and try again. Note: we haven't changed changeDelta. So the callers loop
// will just repeat this until we get to a node or token that we can skip over.
_oldSourceUnitCursor.moveToFirstChild();
}
else {
_oldSourceUnitCursor.moveToNextSibling();
// Get our change delta closer to 0 as we skip past this item.
_changeDelta += fullWidth(currentNodeOrToken);
// If this was a node, then our changeDelta is 0 or negative. If this was a
// token, then we could still be negative (and we have to read another token),
// we could be zero (we're done), or we could be positive (we've moved ahead
// of the new text). Only if we're negative will we continue looping.
}
}
// At this point, we must be either:
// a) done with the cursor
// b) (ideally) caught up to the new text position.
// c) ahead of the new text position.
// In case 'b' we can try to reuse a node from teh old tree.
// Debug.assert(_oldSourceUnitCursor.isFinished() || _changeDelta >= 0);
}
function intersectsWithChangeRangeSpanInOriginalText(start: number, length: number) {
return !isPastChangeRange() && _changeRange.span().intersectsWith(start, length);
}
function tryGetNodeFromOldSourceUnit(): ISyntaxNode {
// Debug.assert(canReadFromOldSourceUnit());
// Keep moving the cursor down to the first node that is safe to return. A node is
// safe to return if:
// a) it does not intersect the changed text.
// b) it does not contain skipped text.
// c) it does not have any zero width tokens in it.
// d) it does not have a regex token in it.
// e) we are still in the same strict or non-strict state that the node was originally parsed in.
while (true) {
var node = _oldSourceUnitCursor.currentNode();
if (node === null) {
// Couldn't even read a node, nothing to return.
return null;
}
if (!intersectsWithChangeRangeSpanInOriginalText(absolutePosition(), fullWidth(node))) {
// Didn't intersect with the change range.
var isIncrementallyUnusuable = TypeScript.isIncrementallyUnusable(node);
if (!isIncrementallyUnusuable) {
// Didn't contain anything that would make it unusable. Awesome. This is
// a node we can reuse.
return node;
}
}
// We couldn't use currentNode. Try to move to its first child (in case that's a
// node). If it is we can try using that. Otherwise we'll just bail out in the
// next iteration of the loop.
_oldSourceUnitCursor.moveToFirstChild();
}
}
function canReuseTokenFromOldSourceUnit(position: number, token: ISyntaxToken): boolean {
// A token is safe to return if:
// a) it does not intersect the changed text.
// b) it does not contain skipped text.
// c) it is not zero width.
// d) it is not a contextual parser token.
//
// NOTE: It is safe to get a token regardless of what our strict context was/is. That's
// because the strict context doesn't change what tokens are scanned, only how the
// parser reacts to them.
//
// NOTE: we don't mark a keyword that was converted to an identifier as 'incrementally
// unusable. This is because we don't want to mark it's containing parent node as
// unusable. i.e. if i have this: "public Foo(string: Type) { }", then that *entire* node
// is reusuable even though "string" was converted to an identifier. However, we still
// need to make sure that if that the parser asks for a *token* we don't return it.
// Converted identifiers can't ever be created by the scanner, and as such, should not
// be returned by this source.
if (token !== null) {
if (!intersectsWithChangeRangeSpanInOriginalText(position, token.fullWidth())) {
// Didn't intersect with the change range.
if (!token.isIncrementallyUnusable() && !Scanner.isContextualToken(token)) {
// Didn't contain anything that would make it unusable. Awesome. This is
// a token we can reuse.
return true;
}
}
}
return false;
}
function tryGetTokenFromOldSourceUnit(): ISyntaxToken {
// Debug.assert(canReadFromOldSourceUnit());
// get the current token that the cursor is pointing at.
var token = _oldSourceUnitCursor.currentToken();
return canReuseTokenFromOldSourceUnit(absolutePosition(), token)
? token : null;
}
function peekToken(n: number): ISyntaxToken {
if (canReadFromOldSourceUnit()) {
var token = tryPeekTokenFromOldSourceUnit(n);
if (token !== null) {
return token;
}
}
// Couldn't peek this far in the old tree. Get the token from the new text.
return _scannerParserSource.peekToken(n);
}
function tryPeekTokenFromOldSourceUnit(n: number): ISyntaxToken {
// Debug.assert(canReadFromOldSourceUnit());
// clone the existing cursor so we can move it forward and then restore ourselves back
// to where we started from.
var cursorClone = cloneSyntaxCursor(_oldSourceUnitCursor);
var token = tryPeekTokenFromOldSourceUnitWorker(n);
returnSyntaxCursor(_oldSourceUnitCursor);
_oldSourceUnitCursor = cursorClone;
return token;
}
function tryPeekTokenFromOldSourceUnitWorker(n: number): ISyntaxToken {
// In order to peek the 'nth' token we need all the tokens up to that point. That way
// we know we know position that the nth token is at. The position is necessary so
// that we can test if this token (or any that precede it cross the change range).
var currentPosition = absolutePosition();
// First, make sure the cursor is pointing at a token.
_oldSourceUnitCursor.moveToFirstToken();
// Now, keep walking forward to successive tokens.
for (var i = 0; i < n; i++) {
var interimToken = _oldSourceUnitCursor.currentToken();
if (!canReuseTokenFromOldSourceUnit(currentPosition, interimToken)) {
return null;
}
currentPosition += interimToken.fullWidth();
_oldSourceUnitCursor.moveToNextSibling();
}
var token = _oldSourceUnitCursor.currentToken();
return canReuseTokenFromOldSourceUnit(currentPosition, token)
? token : null;
}
function consumeNode(node: ISyntaxNode): void {
// A node could have only come from the old source unit cursor. Update it and our
// current state.
// Debug.assert(_changeDelta === 0);
// Debug.assert(currentNode() === node);
_oldSourceUnitCursor.moveToNextSibling();
// Update the underlying source with where it should now be currently pointin.
var _absolutePosition = absolutePosition() + fullWidth(node);
_scannerParserSource.resetToPosition(_absolutePosition);
// Debug.assert(previousToken !== null);
// Debug.assert(previousToken.width() > 0);
//if (!isPastChangeRange()) {
// // If we still have a change range, then this node must have ended before the
// // change range starts. Thus, we don't need to call 'skipPastChanges'.
// Debug.assert(absolutePosition() < _changeRange.span().start());
//}
}
function consumeToken(currentToken: ISyntaxToken): void {
// This token may have come from the old source unit, or from the new text. Handle
// both accordingly.
if (_oldSourceUnitCursor.currentToken() === currentToken) {
// The token came from the old source unit. So our tree and text must be in sync.
// Debug.assert(_changeDelta === 0);
// Move the cursor past this token.
_oldSourceUnitCursor.moveToNextSibling();
// Debug.assert(!_normalParserSource.isPinned());
// Update the underlying source with where it should now be currently pointing. We
// don't need to do this when the token came from the new text as the source will
// automatically be placed in the right position.
var _absolutePosition = absolutePosition() + currentToken.fullWidth();
_scannerParserSource.resetToPosition(_absolutePosition);
// Debug.assert(previousToken !== null);
// Debug.assert(previousToken.width() > 0);
//if (!isPastChangeRange()) {
// // If we still have a change range, then this token must have ended before the
// // change range starts. Thus, we don't need to call 'skipPastChanges'.
// Debug.assert(absolutePosition() < _changeRange.span().start());
//}
}
else {
// the token came from the new text. That means the normal source moved forward,
// while the syntax cursor stayed in the same place. Thus our delta moves even
// further back.
_changeDelta -= currentToken.fullWidth();
// Move our underlying source forward.
_scannerParserSource.consumeToken(currentToken);
// Because we read a token from the new text, we may have moved ourselves past the
// change range. If we did, then we may also have to update our change delta to
// compensate for the length change between the old and new text.
if (!isPastChangeRange()) {
// var changeEndInNewText = _changeRange.span().start() + _changeRange.newLength();
if (absolutePosition() >= _changeRangeNewSpan.end()) {
_changeDelta += _changeRange.newLength() - _changeRange.span().length();
// Once we're past the change range, we no longer need it. Null it out.
// From now on we can check if we're past the change range just by seeing
// if this is null.
_changeRange = null;
}
}
}
}
function isPastChangeRange(): boolean {
return _changeRange === null;
}
return {
text: text,
fileName: fileName,
languageVersion: languageVersion,
currentNode: currentNode,
currentToken: currentToken,
currentContextualToken: currentContextualToken,
peekToken: peekToken,
consumeNode: consumeNode,
consumeToken: consumeToken,
getRewindPoint: getRewindPoint,
rewind: rewind,
releaseRewindPoint: releaseRewindPoint,
tokenDiagnostics: tokenDiagnostics,
release: release
};
}
interface SyntaxCursorPiece {
element: ISyntaxElement;
indexInParent: number
}
function createSyntaxCursorPiece(element: ISyntaxElement, indexInParent: number) {
return { element: element, indexInParent: indexInParent };
}
// Pool syntax cursors so we don't churn too much memory when we need temporary cursors.
// i.e. when we're speculatively parsing, we can cheaply get a pooled cursor and then
// return it when we no longer need it.
var syntaxCursorPool: SyntaxCursor[] = [];
var syntaxCursorPoolCount: number = 0;
function returnSyntaxCursor(cursor: SyntaxCursor): void {
// Make sure the cursor isn't holding onto any syntax elements. We don't want to leak
// them when we return the cursor to the pool.
cursor.clean();
syntaxCursorPool[syntaxCursorPoolCount] = cursor;
syntaxCursorPoolCount++;
}
function getSyntaxCursor(): SyntaxCursor {
// Get an existing cursor from the pool if we have one. Or create a new one if we don't.
var cursor = syntaxCursorPoolCount > 0
? syntaxCursorPool[syntaxCursorPoolCount - 1]
: createSyntaxCursor();
if (syntaxCursorPoolCount > 0) {
// If we reused an existing cursor, take it out of the pool so no one else uses it.
syntaxCursorPoolCount--;
syntaxCursorPool[syntaxCursorPoolCount] = null;
}
return cursor;
}
function cloneSyntaxCursor(cursor: SyntaxCursor): SyntaxCursor {
var newCursor = getSyntaxCursor();
// Make the new cursor a *deep* copy of the cursor passed in. This ensures each cursor can
// be moved without affecting the other.
newCursor.deepCopyFrom(cursor);
return newCursor;
}
interface SyntaxCursor {
pieces: SyntaxCursorPiece[];
clean(): void;
isFinished(): boolean;
moveToFirstChild(): void;
moveToFirstToken(): void;
moveToNextSibling(): void;
currentNodeOrToken(): ISyntaxNodeOrToken;
currentNode(): ISyntaxNode;
currentToken(): ISyntaxToken;
pushElement(element: ISyntaxElement, indexInParent: number): void;
deepCopyFrom(other: SyntaxCursor): void;
}
function createSyntaxCursor(): SyntaxCursor {
// Our list of path pieces. The piece pointed to by 'currentPieceIndex' must be a node or
// token. However, pieces earlier than that may point to list nodes.
//
// For perf we reuse pieces as much as possible. i.e. instead of popping items off the
// list, we just will change currentPieceIndex so we can reuse that piece later.
var pieces: SyntaxCursorPiece[] = [];
var currentPieceIndex: number = -1;
// Cleans up this cursor so that it doesn't have any references to actual syntax nodes.
// This sould be done before returning the cursor to the pool so that the Parser module
// doesn't unnecessarily keep old syntax trees alive.
function clean(): void {
for (var i = 0, n = pieces.length; i < n; i++) {
var piece = pieces[i];
if (piece.element === null) {
break;
}
piece.element = null;
piece.indexInParent = -1;
}
currentPieceIndex = -1;
}
// Makes this cursor into a deep copy of the cursor passed in.
function deepCopyFrom(other: SyntaxCursor): void {
// Debug.assert(currentPieceIndex === -1);
for (var i = 0, n = other.pieces.length; i < n; i++) {
var piece = other.pieces[i];
if (piece.element === null) {
break;
}
pushElement(piece.element, piece.indexInParent);
}
// Debug.assert(currentPieceIndex === other.currentPieceIndex);
}
function isFinished(): boolean {
return currentPieceIndex < 0;
}
function currentNodeOrToken(): ISyntaxNodeOrToken {
if (isFinished()) {
return null;
}
var result = pieces[currentPieceIndex].element;
// The current element must always be a node or a token.
// Debug.assert(result !== null);
// Debug.assert(result.isNode() || result.isToken());
return <ISyntaxNodeOrToken>result;
}
function currentNode(): ISyntaxNode {
var element = currentNodeOrToken();
return isNode(element) ? <ISyntaxNode>element : null;
}
function moveToFirstChild() {
var nodeOrToken = currentNodeOrToken();
if (nodeOrToken === null) {
return;
}
if (isToken(nodeOrToken)) {
// If we're already on a token, there's nothing to do.
return;
}
// The last element must be a token or a node.
// Debug.assert(isNode(nodeOrToken));
// Either the node has some existent child, then move to it. if it doesn't, then it's
// an empty node. Conceptually the first child of an empty node is really just the
// next sibling of the empty node.
for (var i = 0, n = childCount(nodeOrToken); i < n; i++) {
var child = childAt(nodeOrToken, i);
if (child !== null && !isShared(child)) {
// Great, we found a real child. Push that.
pushElement(child, /*indexInParent:*/ i);
// If it was a list, make sure we're pointing at its first element. We know we
// must have one because this is a non-shared list.
moveToFirstChildIfList();
return;
}
}
// This element must have been an empty node. Moving to its 'first child' is equivalent to just
// moving to the next sibling.
// Debug.assert(fullWidth(nodeOrToken) === 0);
moveToNextSibling();
}
function moveToNextSibling(): void {
while (!isFinished()) {
// first look to our parent and see if it has a sibling of us that we can move to.
var currentPiece = pieces[currentPieceIndex];
var parent = currentPiece.element.parent;
// We start searching at the index one past our own index in the parent.
for (var i = currentPiece.indexInParent + 1, n = childCount(parent); i < n; i++) {
var sibling = childAt(parent, i);
if (sibling !== null && !isShared(sibling)) {
// We found a good sibling that we can move to. Just reuse our existing piece
// so we don't have to push/pop.
currentPiece.element = sibling;
currentPiece.indexInParent = i;
// The sibling might have been a list. Move to it's first child. it must have
// one since this was a non-shared element.
moveToFirstChildIfList();
return;
}
}
// Didn't have a sibling for this element. Go up to our parent and get its sibling.
// Clear the data from the old piece. We don't want to keep any elements around
// unintentionally.
currentPiece.element = null;
currentPiece.indexInParent = -1;
// Point at the parent. if we move past the top of the path, then we're finished.
currentPieceIndex--;
}
}
function moveToFirstChildIfList(): void {
var element = pieces[currentPieceIndex].element;
if (isList(element) || isSeparatedList(element)) {
// We cannot ever get an empty list in our piece path. Empty lists are 'shared' and
// we make sure to filter that out before pushing any children.
// Debug.assert(childCount(element) > 0);
pushElement(childAt(element, 0), /*indexInParent:*/ 0);
}
}
function pushElement(element: ISyntaxElement, indexInParent: number): void {
// Debug.assert(element !== null);
// Debug.assert(indexInParent >= 0);
currentPieceIndex++;
// Reuse an existing piece if we have one. Otherwise, push a new piece to our list.
if (currentPieceIndex === pieces.length) {
pieces.push(createSyntaxCursorPiece(element, indexInParent));
}
else {
var piece = pieces[currentPieceIndex];
piece.element = element;
piece.indexInParent = indexInParent;
}
}
function moveToFirstToken(): void {
while (!isFinished()) {
var element = pieces[currentPieceIndex].element;
if (isNode(element)) {
moveToFirstChild();
continue;
}
// Debug.assert(isToken(element));
return;
}
}
function currentToken(): ISyntaxToken {
moveToFirstToken();
var element = currentNodeOrToken();
// Debug.assert(element === null || element.isToken());
return element === null ? null : <ISyntaxToken>element;
}
return {
pieces: pieces,
clean: clean,
isFinished: isFinished,
moveToFirstChild: moveToFirstChild,
moveToFirstToken: moveToFirstToken,
moveToNextSibling: moveToNextSibling,
currentNodeOrToken: currentNodeOrToken,
currentNode: currentNode,
currentToken: currentToken,
pushElement: pushElement,
deepCopyFrom: deepCopyFrom
};
}
// A simple walker we use to hit all the tokens of a node and update their positions when they
// are reused in a different location because of an incremental parse.
class SetTokenFullStartWalker extends SyntaxWalker {
public position: number;
public visitToken(token: ISyntaxToken): void {
var position = this.position;
token.setFullStart(position);
this.position = position + token.fullWidth();
}
}
var setTokenFullStartWalker = new SetTokenFullStartWalker();
export function parse(oldSyntaxTree: SyntaxTree, textChangeRange: TextChangeRange, newText: ISimpleText): SyntaxTree {
Debug.assert(oldSyntaxTree.isConcrete(), "Can only incrementally parse a concrete syntax tree.");
if (textChangeRange.isUnchanged()) {
return oldSyntaxTree;
}
return Parser.parseSource(createParserSource(oldSyntaxTree, textChangeRange, newText), oldSyntaxTree.isDeclaration());
}
}
+3
View File
@@ -0,0 +1,3 @@
module TypeScript {
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More