diff --git a/Jakefile b/Jakefile
index 039c085ba12..89586e8ca62 100644
--- a/Jakefile
+++ b/Jakefile
@@ -35,6 +35,7 @@ var compilerSources = [
"types.ts",
"scanner.ts",
"parser.ts",
+ "utilities.ts",
"binder.ts",
"checker.ts",
"emitter.ts",
@@ -47,26 +48,53 @@ var compilerSources = [
var servicesSources = [
"core.ts",
+ "sys.ts",
"types.ts",
"scanner.ts",
"parser.ts",
+ "utilities.ts",
"binder.ts",
"checker.ts",
- "emitter.ts"
+ "emitter.ts",
+ "diagnosticInformationMap.generated.ts"
].map(function (f) {
return path.join(compilerDirectory, f);
}).concat([
"breakpoints.ts",
+ "navigationBar.ts",
+ "outliningElementsCollector.ts",
"services.ts",
"shims.ts",
"signatureHelp.ts",
"utilities.ts",
- "navigationBar.ts",
- "outliningElementsCollector.ts"
+ "formatting/formatting.ts",
+ "formatting/formattingContext.ts",
+ "formatting/formattingRequestKind.ts",
+ "formatting/formattingScanner.ts",
+ "formatting/references.ts",
+ "formatting/rule.ts",
+ "formatting/ruleAction.ts",
+ "formatting/ruleDescriptor.ts",
+ "formatting/ruleFlag.ts",
+ "formatting/ruleOperation.ts",
+ "formatting/ruleOperationContext.ts",
+ "formatting/rules.ts",
+ "formatting/rulesMap.ts",
+ "formatting/rulesProvider.ts",
+ "formatting/smartIndenter.ts",
+ "formatting/tokenRange.ts"
].map(function (f) {
return path.join(servicesDirectory, f);
}));
+var definitionsRoots = [
+ "compiler/types.d.ts",
+ "compiler/scanner.d.ts",
+ "compiler/parser.d.ts",
+ "compiler/checker.d.ts",
+ "services/services.d.ts",
+];
+
var harnessSources = [
"harness.ts",
"sourceMapRecorder.ts",
@@ -149,25 +177,48 @@ var compilerFilename = "tsc.js";
* @param prefixes: a list of files to prepend to the target file
* @param useBuiltCompiler: true to use the built compiler, false to use the LKG
* @param noOutFile: true to compile without using --out
+ * @param generateDeclarations: true to compile using --declaration
+ * @param outDir: true to compile using --outDir
+ * @param keepComments: false to compile using --removeComments
+ * @param callback: a function to execute after the compilation process ends
*/
-function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, noOutFile, generateDeclarations, callback) {
+function compileFile(outFile, sources, prereqs, prefixes, useBuiltCompiler, noOutFile, generateDeclarations, outDir, keepComments, noResolve, callback) {
file(outFile, prereqs, function() {
var dir = useBuiltCompiler ? builtLocalDirectory : LKGDirectory;
- var options = "-removeComments --module commonjs -noImplicitAny ";
+ var options = "--module commonjs -noImplicitAny";
+
+ if (!keepComments) {
+ options += " -removeComments";
+ }
+
if (generateDeclarations) {
- options += "--declaration ";
+ options += " --declaration";
}
if (useDebugMode) {
- options += "--preserveConstEnums ";
+ options += " --preserveConstEnums";
+ }
+
+ if (outDir) {
+ options += " --outDir " + outDir;
+ }
+
+ if (!noOutFile) {
+ options += " --out " + outFile;
+ }
+
+ if(noResolve) {
+ options += " --noResolve";
+ }
+
+ if (useDebugMode) {
+ options += " -sourcemap -mapRoot file:///" + path.resolve(path.dirname(outFile));
}
var cmd = host + " " + dir + compilerFilename + " " + options + " ";
- cmd = cmd + sources.join(" ") + (!noOutFile ? " -out " + outFile : "");
- if (useDebugMode) {
- cmd = cmd + " -sourcemap -mapRoot file:///" + path.resolve(path.dirname(outFile));
- }
+ cmd = cmd + sources.join(" ");
console.log(cmd + "\n");
+
var ex = jake.createExec([cmd]);
// Add listeners for output and error
ex.addListener("stdout", function(output) {
@@ -260,24 +311,38 @@ var tscFile = path.join(builtLocalDirectory, compilerFilename);
compileFile(tscFile, compilerSources, [builtLocalDirectory, copyright].concat(compilerSources), [copyright], /*useBuiltCompiler:*/ false);
var servicesFile = path.join(builtLocalDirectory, "typescriptServices.js");
-var servicesDefinitionsFile = path.join(builtLocalDirectory, "typescriptServices.d.ts");
+compileFile(servicesFile, servicesSources,[builtLocalDirectory, copyright].concat(servicesSources), [copyright], /*useBuiltCompiler*/ true);
-compileFile(servicesFile,
- servicesSources,
- [builtLocalDirectory, copyright].concat(servicesSources),
- [copyright],
+var nodeDefinitionsFile = path.join(builtLocalDirectory, "typescript.d.ts");
+var standaloneDefinitionsFile = path.join(builtLocalDirectory, "typescriptServices.d.ts");
+var tempDirPath = path.join(builtLocalDirectory, "temptempdir");
+compileFile(nodeDefinitionsFile, servicesSources,[builtLocalDirectory, copyright].concat(servicesSources),
+ /*prefixes*/ undefined,
/*useBuiltCompiler*/ true,
- /*noOutFile*/ false,
+ /*noOutFile*/ true,
/*generateDeclarations*/ true,
- /*callback*/ fixDeclarationFile);
+ /*outDir*/ tempDirPath,
+ /*keepComments*/ true,
+ /*noResolve*/ true,
+ /*callback*/ function () {
+ concatenateFiles(standaloneDefinitionsFile, definitionsRoots.map(function (f) {
+ return path.join(tempDirPath, f);
+ }));
+ prependFile(copyright, standaloneDefinitionsFile);
-function fixDeclarationFile() {
- fs.appendFileSync(servicesDefinitionsFile, os.EOL + "export = ts;")
-}
+ // Create the node definition file by replacing 'ts' module with '"typescript"' as a module.
+ jake.cpR(standaloneDefinitionsFile, nodeDefinitionsFile, {silent: true});
+ var definitionFileContents = fs.readFileSync(nodeDefinitionsFile).toString();
+ definitionFileContents = definitionFileContents.replace(/declare module ts/g, 'declare module "typescript"');
+ fs.writeFileSync(nodeDefinitionsFile, definitionFileContents);
+
+ // Delete the temp dir
+ jake.rmRf(tempDirPath, {silent: true});
+ });
// Local target to build the compiler and services
desc("Builds the full compiler and services");
-task("local", ["generate-diagnostics", "lib", tscFile, servicesFile]);
+task("local", ["generate-diagnostics", "lib", tscFile, servicesFile, nodeDefinitionsFile]);
// Local target to build the compiler and services
desc("Sets release mode flag");
@@ -328,7 +393,7 @@ task("generate-spec", [specMd])
// Makes a new LKG. This target does not build anything, but errors if not all the outputs are present in the built/local directory
desc("Makes a new LKG out of the built js files");
task("LKG", ["clean", "release", "local"].concat(libraryTargets), function() {
- var expectedFiles = [tscFile, servicesFile, servicesDefinitionsFile].concat(libraryTargets);
+ var expectedFiles = [tscFile, servicesFile, nodeDefinitionsFile, standaloneDefinitionsFile].concat(libraryTargets);
var missingFiles = expectedFiles.filter(function (f) {
return !fs.existsSync(f);
});
diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 1e8a87bc4d4..cb9912c47d0 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -4,57 +4,12 @@
///
///
///
+///
module ts {
var nextSymbolId = 1;
var nextNodeId = 1;
- var nextMergeId = 1;
-
- export function getDeclarationOfKind(symbol: Symbol, kind: SyntaxKind): Declaration {
- var declarations = symbol.declarations;
- for (var i = 0; i < declarations.length; i++) {
- var declaration = declarations[i];
- if (declaration.kind === kind) {
- return declaration;
- }
- }
-
- return undefined;
- }
-
- export interface StringSymbolWriter extends SymbolWriter {
- string(): string;
- }
-
- // Pool writers to avoid needing to allocate them for every symbol we write.
- var stringWriters: StringSymbolWriter[] = [];
- export function getSingleLineStringWriter(): StringSymbolWriter {
- if (stringWriters.length == 0) {
- var str = "";
-
- var writeText: (text: string) => void = text => str += text;
- return {
- string: () => str,
- writeKeyword: writeText,
- writeOperator: writeText,
- writePunctuation: writeText,
- writeSpace: writeText,
- writeStringLiteral: writeText,
- writeParameter: writeText,
- writeSymbol: writeText,
-
- // Completely ignore indentation for string writers. And map newlines to
- // a single space.
- writeLine: () => str += " ",
- increaseIndent: () => { },
- decreaseIndent: () => { },
- clear: () => str = "",
- trackSymbol: () => { }
- };
- }
-
- return stringWriters.pop();
- }
+ var nextMergeId = 1;
/// fullTypeCheck denotes if this instance of the typechecker will be used to get semantic diagnostics.
/// If fullTypeCheck === true, then the typechecker should do every possible check to produce all errors
@@ -1012,11 +967,6 @@ module ts {
};
}
- function releaseStringWriter(writer: StringSymbolWriter) {
- writer.clear()
- stringWriters.push(writer);
- }
-
function writeKeyword(writer: SymbolWriter, kind: SyntaxKind) {
writer.writeKeyword(tokenToString(kind));
}
diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts
index d810c5126fa..d2a5971a078 100644
--- a/src/compiler/parser.ts
+++ b/src/compiler/parser.ts
@@ -1,41 +1,11 @@
///
///
///
+///
module ts {
var nodeConstructors = new Array Node>(SyntaxKind.Count);
- export function getFullWidth(node: Node) {
- return node.end - node.pos;
- }
-
- function hasFlag(val: number, flag: number): boolean {
- return (val & flag) !== 0;
- }
-
- // Returns true if this node contains a parse error anywhere underneath it.
- export function containsParseError(node: Node): boolean {
- if (!hasFlag(node.parserContextFlags, ParserContextFlags.HasPropagatedChildContainsErrorFlag)) {
- // A node is considered to contain a parse error if:
- // a) the parser explicitly marked that it had an error
- // b) any of it's children reported that it had an error.
- var val = hasFlag(node.parserContextFlags, ParserContextFlags.ContainsError) ||
- forEachChild(node, containsParseError);
-
- // If so, mark ourselves accordingly.
- if (val) {
- node.parserContextFlags |= ParserContextFlags.ContainsError;
- }
-
- // Also mark that we've propogated the child information to this node. This way we can
- // always consult the bit directly on this node without needing to check its children
- // again.
- node.parserContextFlags |= ParserContextFlags.HasPropagatedChildContainsErrorFlag;
- }
-
- return hasFlag(node.parserContextFlags, ParserContextFlags.ContainsError);
- }
-
export function getNodeConstructor(kind: SyntaxKind): new () => Node {
return nodeConstructors[kind] || (nodeConstructors[kind] = objectAllocator.getNodeConstructor(kind));
}
@@ -44,140 +14,6 @@ module ts {
return new (getNodeConstructor(kind))();
}
- export function getSourceFileOfNode(node: Node): SourceFile {
- while (node && node.kind !== SyntaxKind.SourceFile) node = node.parent;
- return node;
- }
-
- // This is a useful function for debugging purposes.
- export function nodePosToString(node: Node): string {
- var file = getSourceFileOfNode(node);
- var loc = file.getLineAndCharacterFromPosition(node.pos);
- return file.filename + "(" + loc.line + "," + loc.character + ")";
- }
-
- export function getStartPosOfNode(node: Node): number {
- return node.pos;
- }
-
- export function isMissingNode(node: Node) {
- return node.pos === node.end && node.kind !== SyntaxKind.EndOfFileToken;
- }
-
- export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile): number {
- // With nodes that have no width (i.e. 'Missing' nodes), we actually *don't*
- // want to skip trivia because this will launch us forward to the next token.
- if (isMissingNode(node)) {
- return node.pos;
- }
-
- return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos);
- }
-
- export function getSourceTextOfNodeFromSourceFile(sourceFile: SourceFile, node: Node): string {
- if (isMissingNode(node)) {
- return "";
- }
-
- var text = sourceFile.text;
- return text.substring(skipTrivia(text, node.pos), node.end);
- }
-
- export function getTextOfNodeFromSourceText(sourceText: string, node: Node): string {
- if (isMissingNode(node)) {
- return "";
- }
-
- return sourceText.substring(skipTrivia(sourceText, node.pos), node.end);
- }
-
- export function getTextOfNode(node: Node): string {
- return getSourceTextOfNodeFromSourceFile(getSourceFileOfNode(node), node);
- }
-
- // Add an extra underscore to identifiers that start with two underscores to avoid issues with magic names like '__proto__'
- export function escapeIdentifier(identifier: string): string {
- return identifier.length >= 2 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ ? "_" + identifier : identifier;
- }
-
- // Remove extra underscore from escaped identifier
- export function unescapeIdentifier(identifier: string): string {
- return identifier.length >= 3 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ && identifier.charCodeAt(2) === CharacterCodes._ ? identifier.substr(1) : identifier;
- }
-
- // Return display name of an identifier
- // Computed property names will just be emitted as "[]", where is the source
- // text of the expression in the computed property.
- export function declarationNameToString(name: DeclarationName) {
- return getFullWidth(name) === 0 ? "(Missing)" : getTextOfNode(name);
- }
-
- export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): Diagnostic {
- node = getErrorSpanForNode(node);
- var file = getSourceFileOfNode(node);
-
- var start = getFullWidth(node) === 0 ? node.pos : skipTrivia(file.text, node.pos);
- var length = node.end - start;
-
- return createFileDiagnostic(file, start, length, message, arg0, arg1, arg2);
- }
-
- 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, newLine);
- }
-
- export function getErrorSpanForNode(node: Node): Node {
- var errorSpan: Node;
- switch (node.kind) {
- // This list is a work in progress. Add missing node kinds to improve their error
- // spans.
- case SyntaxKind.VariableDeclaration:
- case SyntaxKind.BindingElement:
- case SyntaxKind.ClassDeclaration:
- case SyntaxKind.InterfaceDeclaration:
- case SyntaxKind.ModuleDeclaration:
- case SyntaxKind.EnumDeclaration:
- case SyntaxKind.EnumMember:
- errorSpan = (node).name;
- break;
- }
-
- // We now have the ideal error span, but it may be a node that is optional and absent
- // (e.g. the name of a function expression), in which case errorSpan will be undefined.
- // Alternatively, it might be required and missing (e.g. the name of a module), in which
- // case its pos will equal its end (length 0). In either of these cases, we should fall
- // back to the original node that the error was issued on.
- return errorSpan && errorSpan.pos < errorSpan.end ? errorSpan : node;
- }
-
- export function isExternalModule(file: SourceFile): boolean {
- return file.externalModuleIndicator !== undefined;
- }
-
- export function isDeclarationFile(file: SourceFile): boolean {
- return (file.flags & NodeFlags.DeclarationFile) !== 0;
- }
-
- export function isConstEnumDeclaration(node: Node): boolean {
- return node.kind === SyntaxKind.EnumDeclaration && isConst(node);
- }
-
- export function isConst(node: Node): boolean {
- return !!(node.flags & NodeFlags.Const);
- }
-
- export function isLet(node: Node): boolean {
- return !!(node.flags & NodeFlags.Let);
- }
-
- export function isPrologueDirective(node: Node): boolean {
- return node.kind === SyntaxKind.ExpressionStatement && (node).expression.kind === SyntaxKind.StringLiteral;
- }
-
function isEvalOrArgumentsIdentifier(node: Node): boolean {
return node.kind === SyntaxKind.Identifier &&
(node).text &&
@@ -190,36 +26,6 @@ module ts {
return ((node).expression).text === "use strict";
}
- export function getLeadingCommentRangesOfNode(node: Node, sourceFileOfNode?: SourceFile) {
- sourceFileOfNode = sourceFileOfNode || getSourceFileOfNode(node);
-
- // If parameter/type parameter, the prev token trailing comments are part of this node too
- if (node.kind === SyntaxKind.Parameter || node.kind === SyntaxKind.TypeParameter) {
- // e.g. (/** blah */ a, /** blah */ b);
- return concatenate(getTrailingCommentRanges(sourceFileOfNode.text, node.pos),
- // e.g.: (
- // /** blah */ a,
- // /** blah */ b);
- getLeadingCommentRanges(sourceFileOfNode.text, node.pos));
- }
- else {
- return getLeadingCommentRanges(sourceFileOfNode.text, node.pos);
- }
- }
-
- export function getJsDocComments(node: Node, sourceFileOfNode: SourceFile) {
- return filter(getLeadingCommentRangesOfNode(node, sourceFileOfNode), isJsDocComment);
-
- function isJsDocComment(comment: CommentRange) {
- // True if the comment starts with '/**' but not if it is '/**/'
- return sourceFileOfNode.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk &&
- sourceFileOfNode.text.charCodeAt(comment.pos + 2) === CharacterCodes.asterisk &&
- sourceFileOfNode.text.charCodeAt(comment.pos + 3) !== CharacterCodes.slash;
- }
- }
-
- export var fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*/
-
// Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes
// stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise,
// embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns
@@ -466,425 +272,6 @@ module ts {
}
}
- // Warning: This has the same semantics as the forEach family of functions,
- // in that traversal terminates in the event that 'visitor' supplies a truthy value.
- export function forEachReturnStatement(body: Block, visitor: (stmt: ReturnStatement) => T): T {
-
- return traverse(body);
-
- function traverse(node: Node): T {
- switch (node.kind) {
- case SyntaxKind.ReturnStatement:
- return visitor(node);
- case SyntaxKind.Block:
- case SyntaxKind.IfStatement:
- case SyntaxKind.DoStatement:
- case SyntaxKind.WhileStatement:
- case SyntaxKind.ForStatement:
- case SyntaxKind.ForInStatement:
- case SyntaxKind.WithStatement:
- case SyntaxKind.SwitchStatement:
- case SyntaxKind.CaseClause:
- case SyntaxKind.DefaultClause:
- case SyntaxKind.LabeledStatement:
- case SyntaxKind.TryStatement:
- case SyntaxKind.TryBlock:
- case SyntaxKind.CatchClause:
- case SyntaxKind.FinallyBlock:
- return forEachChild(node, traverse);
- }
- }
- }
-
- export function isAnyFunction(node: Node): boolean {
- if (node) {
- switch (node.kind) {
- case SyntaxKind.Constructor:
- case SyntaxKind.FunctionExpression:
- case SyntaxKind.FunctionDeclaration:
- case SyntaxKind.ArrowFunction:
- case SyntaxKind.MethodDeclaration:
- case SyntaxKind.MethodSignature:
- case SyntaxKind.GetAccessor:
- case SyntaxKind.SetAccessor:
- case SyntaxKind.CallSignature:
- case SyntaxKind.ConstructSignature:
- case SyntaxKind.IndexSignature:
- case SyntaxKind.FunctionType:
- case SyntaxKind.ConstructorType:
- case SyntaxKind.FunctionExpression:
- case SyntaxKind.ArrowFunction:
- case SyntaxKind.FunctionDeclaration:
- return true;
- }
- }
-
- return false;
- }
-
- export function isFunctionBlock(node: Node) {
- return node && node.kind === SyntaxKind.Block && isAnyFunction(node.parent);
- }
-
- export function isObjectLiteralMethod(node: Node) {
- return node && node.kind === SyntaxKind.MethodDeclaration && node.parent.kind === SyntaxKind.ObjectLiteralExpression;
- }
-
- export function getContainingFunction(node: Node): FunctionLikeDeclaration {
- while (true) {
- node = node.parent;
- if (!node || isAnyFunction(node)) {
- return node;
- }
- }
- }
-
- export function getThisContainer(node: Node, includeArrowFunctions: boolean): Node {
- while (true) {
- node = node.parent;
- if (!node) {
- return undefined;
- }
- switch (node.kind) {
- case SyntaxKind.ArrowFunction:
- if (!includeArrowFunctions) {
- continue;
- }
- // Fall through
- case SyntaxKind.FunctionDeclaration:
- case SyntaxKind.FunctionExpression:
- case SyntaxKind.ModuleDeclaration:
- case SyntaxKind.PropertyDeclaration:
- case SyntaxKind.PropertySignature:
- case SyntaxKind.MethodDeclaration:
- case SyntaxKind.MethodSignature:
- case SyntaxKind.Constructor:
- case SyntaxKind.GetAccessor:
- case SyntaxKind.SetAccessor:
- case SyntaxKind.EnumDeclaration:
- case SyntaxKind.SourceFile:
- return node;
- }
- }
- }
-
- export function getSuperContainer(node: Node): Node {
- while (true) {
- node = node.parent;
- if (!node) {
- return undefined;
- }
- switch (node.kind) {
- case SyntaxKind.PropertyDeclaration:
- case SyntaxKind.PropertySignature:
- case SyntaxKind.MethodDeclaration:
- case SyntaxKind.MethodSignature:
- case SyntaxKind.Constructor:
- case SyntaxKind.GetAccessor:
- case SyntaxKind.SetAccessor:
- return node;
- }
- }
- }
-
- export function getInvokedExpression(node: CallLikeExpression): Expression {
- if (node.kind === SyntaxKind.TaggedTemplateExpression) {
- return (node).tag;
- }
-
- // Will either be a CallExpression or NewExpression.
- return (node).expression;
- }
-
- export function isExpression(node: Node): boolean {
- switch (node.kind) {
- case SyntaxKind.ThisKeyword:
- case SyntaxKind.SuperKeyword:
- case SyntaxKind.NullKeyword:
- case SyntaxKind.TrueKeyword:
- case SyntaxKind.FalseKeyword:
- case SyntaxKind.RegularExpressionLiteral:
- case SyntaxKind.ArrayLiteralExpression:
- case SyntaxKind.ObjectLiteralExpression:
- case SyntaxKind.PropertyAccessExpression:
- case SyntaxKind.ElementAccessExpression:
- case SyntaxKind.CallExpression:
- case SyntaxKind.NewExpression:
- case SyntaxKind.TaggedTemplateExpression:
- case SyntaxKind.TypeAssertionExpression:
- case SyntaxKind.ParenthesizedExpression:
- case SyntaxKind.FunctionExpression:
- case SyntaxKind.ArrowFunction:
- case SyntaxKind.VoidExpression:
- case SyntaxKind.DeleteExpression:
- case SyntaxKind.TypeOfExpression:
- case SyntaxKind.PrefixUnaryExpression:
- case SyntaxKind.PostfixUnaryExpression:
- case SyntaxKind.BinaryExpression:
- case SyntaxKind.ConditionalExpression:
- case SyntaxKind.TemplateExpression:
- case SyntaxKind.NoSubstitutionTemplateLiteral:
- case SyntaxKind.OmittedExpression:
- return true;
- case SyntaxKind.QualifiedName:
- while (node.parent.kind === SyntaxKind.QualifiedName) {
- node = node.parent;
- }
-
- return node.parent.kind === SyntaxKind.TypeQuery;
- case SyntaxKind.Identifier:
- if (node.parent.kind === SyntaxKind.TypeQuery) {
- return true;
- }
- // fall through
- case SyntaxKind.NumericLiteral:
- case SyntaxKind.StringLiteral:
- var parent = node.parent;
- switch (parent.kind) {
- case SyntaxKind.VariableDeclaration:
- case SyntaxKind.Parameter:
- case SyntaxKind.PropertyDeclaration:
- case SyntaxKind.PropertySignature:
- case SyntaxKind.EnumMember:
- case SyntaxKind.PropertyAssignment:
- case SyntaxKind.BindingElement:
- return (parent).initializer === node;
- case SyntaxKind.ExpressionStatement:
- case SyntaxKind.IfStatement:
- case SyntaxKind.DoStatement:
- case SyntaxKind.WhileStatement:
- case SyntaxKind.ReturnStatement:
- case SyntaxKind.WithStatement:
- case SyntaxKind.SwitchStatement:
- case SyntaxKind.CaseClause:
- case SyntaxKind.ThrowStatement:
- case SyntaxKind.SwitchStatement:
- return (parent).expression === node;
- case SyntaxKind.ForStatement:
- return (parent).initializer === node ||
- (parent).condition === node ||
- (parent).iterator === node;
- case SyntaxKind.ForInStatement:
- return (parent).variable === node ||
- (parent).expression === node;
- case SyntaxKind.TypeAssertionExpression:
- return node === (parent).expression;
- case SyntaxKind.TemplateSpan:
- return node === (parent).expression;
- default:
- if (isExpression(parent)) {
- return true;
- }
- }
- }
- return false;
- }
-
- export function isExternalModuleImportDeclaration(node: Node) {
- return node.kind === SyntaxKind.ImportDeclaration && (node).moduleReference.kind === SyntaxKind.ExternalModuleReference;
- }
-
- export function getExternalModuleImportDeclarationExpression(node: Node) {
- Debug.assert(isExternalModuleImportDeclaration(node));
- return ((node).moduleReference).expression;
- }
-
- export function isInternalModuleImportDeclaration(node: Node) {
- return node.kind === SyntaxKind.ImportDeclaration && (node).moduleReference.kind !== SyntaxKind.ExternalModuleReference;
- }
-
- export function hasDotDotDotToken(node: Node) {
- return node && node.kind === SyntaxKind.Parameter && (node).dotDotDotToken !== undefined;
- }
-
- export function hasQuestionToken(node: Node) {
- if (node) {
- switch (node.kind) {
- case SyntaxKind.Parameter:
- return (node).questionToken !== undefined;
- case SyntaxKind.MethodDeclaration:
- case SyntaxKind.MethodSignature:
- return (node).questionToken !== undefined;
- case SyntaxKind.ShorthandPropertyAssignment:
- case SyntaxKind.PropertyAssignment:
- case SyntaxKind.PropertyDeclaration:
- case SyntaxKind.PropertySignature:
- return (node).questionToken !== undefined;
- }
- }
-
- return false;
- }
-
- export function hasRestParameters(s: SignatureDeclaration): boolean {
- return s.parameters.length > 0 && s.parameters[s.parameters.length - 1].dotDotDotToken !== undefined;
- }
-
- export function isLiteralKind(kind: SyntaxKind): boolean {
- return SyntaxKind.FirstLiteralToken <= kind && kind <= SyntaxKind.LastLiteralToken;
- }
-
- export function isTextualLiteralKind(kind: SyntaxKind): boolean {
- return kind === SyntaxKind.StringLiteral || kind === SyntaxKind.NoSubstitutionTemplateLiteral;
- }
-
- export function isTemplateLiteralKind(kind: SyntaxKind): boolean {
- return SyntaxKind.FirstTemplateToken <= kind && kind <= SyntaxKind.LastTemplateToken;
- }
-
- export function isBindingPattern(node: Node) {
- return node.kind === SyntaxKind.ArrayBindingPattern || node.kind === SyntaxKind.ObjectBindingPattern;
- }
-
- export function isInAmbientContext(node: Node): boolean {
- while (node) {
- if (node.flags & (NodeFlags.Ambient | NodeFlags.DeclarationFile)) return true;
- node = node.parent;
- }
- return false;
- }
-
- export function isDeclaration(node: Node): boolean {
- switch (node.kind) {
- case SyntaxKind.TypeParameter:
- case SyntaxKind.Parameter:
- case SyntaxKind.VariableDeclaration:
- case SyntaxKind.BindingElement:
- case SyntaxKind.PropertyDeclaration:
- case SyntaxKind.PropertySignature:
- case SyntaxKind.PropertyAssignment:
- case SyntaxKind.ShorthandPropertyAssignment:
- case SyntaxKind.EnumMember:
- case SyntaxKind.MethodDeclaration:
- case SyntaxKind.MethodSignature:
- case SyntaxKind.FunctionDeclaration:
- case SyntaxKind.GetAccessor:
- case SyntaxKind.SetAccessor:
- case SyntaxKind.Constructor:
- case SyntaxKind.ClassDeclaration:
- case SyntaxKind.InterfaceDeclaration:
- case SyntaxKind.TypeAliasDeclaration:
- case SyntaxKind.EnumDeclaration:
- case SyntaxKind.ModuleDeclaration:
- case SyntaxKind.ImportDeclaration:
- return true;
- }
- return false;
- }
-
- export function isStatement(n: Node): boolean {
- switch(n.kind) {
- case SyntaxKind.BreakStatement:
- case SyntaxKind.ContinueStatement:
- case SyntaxKind.DebuggerStatement:
- case SyntaxKind.DoStatement:
- case SyntaxKind.ExpressionStatement:
- case SyntaxKind.EmptyStatement:
- case SyntaxKind.ForInStatement:
- case SyntaxKind.ForStatement:
- case SyntaxKind.IfStatement:
- case SyntaxKind.LabeledStatement:
- case SyntaxKind.ReturnStatement:
- case SyntaxKind.SwitchStatement:
- case SyntaxKind.ThrowKeyword:
- case SyntaxKind.TryStatement:
- case SyntaxKind.VariableStatement:
- case SyntaxKind.WhileStatement:
- case SyntaxKind.WithStatement:
- case SyntaxKind.ExportAssignment:
- return true;
- default:
- return false;
- }
- }
-
- // True if the given identifier, string literal, or number literal is the name of a declaration node
- export function isDeclarationOrFunctionExpressionOrCatchVariableName(name: Node): boolean {
- if (name.kind !== SyntaxKind.Identifier && name.kind !== SyntaxKind.StringLiteral && name.kind !== SyntaxKind.NumericLiteral) {
- return false;
- }
-
- var parent = name.parent;
- if (isDeclaration(parent) || parent.kind === SyntaxKind.FunctionExpression) {
- return (parent).name === name;
- }
-
- if (parent.kind === SyntaxKind.CatchClause) {
- return (parent).name === name;
- }
-
- return false;
- }
-
- export function getClassBaseTypeNode(node: ClassDeclaration) {
- var heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ExtendsKeyword);
- return heritageClause && heritageClause.types.length > 0 ? heritageClause.types[0] : undefined;
- }
-
- export function getClassImplementedTypeNodes(node: ClassDeclaration) {
- var heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ImplementsKeyword);
- return heritageClause ? heritageClause.types : undefined;
- }
-
- export function getInterfaceBaseTypeNodes(node: InterfaceDeclaration) {
- var heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ExtendsKeyword);
- return heritageClause ? heritageClause.types : undefined;
- }
-
- export function getHeritageClause(clauses: NodeArray, kind: SyntaxKind) {
- if (clauses) {
- for (var i = 0, n = clauses.length; i < n; i++) {
- if (clauses[i].token === kind) {
- return clauses[i];
- }
- }
- }
-
- return undefined;
- }
-
- export function tryResolveScriptReference(program: Program, sourceFile: SourceFile, reference: FileReference) {
- if (!program.getCompilerOptions().noResolve) {
- var referenceFileName = isRootedDiskPath(reference.filename) ? reference.filename : combinePaths(getDirectoryPath(sourceFile.filename), reference.filename);
- referenceFileName = getNormalizedAbsolutePath(referenceFileName, program.getCompilerHost().getCurrentDirectory());
- return program.getSourceFile(referenceFileName);
- }
- }
-
- export function getAncestor(node: Node, kind: SyntaxKind): Node {
- switch (kind) {
- // special-cases that can be come first
- case SyntaxKind.ClassDeclaration:
- while (node) {
- switch (node.kind) {
- case SyntaxKind.ClassDeclaration:
- return node;
- case SyntaxKind.EnumDeclaration:
- case SyntaxKind.InterfaceDeclaration:
- case SyntaxKind.TypeAliasDeclaration:
- case SyntaxKind.ModuleDeclaration:
- case SyntaxKind.ImportDeclaration:
- // early exit cases - declarations cannot be nested in classes
- return undefined;
- default:
- node = node.parent;
- continue;
- }
- }
- break;
- default:
- while (node) {
- if (node.kind === kind) {
- return node;
- }
- node = node.parent;
- }
- break;
- }
-
- return undefined;
- }
-
const enum ParsingContext {
SourceElements, // Elements in source file
ModuleElements, // Elements in module declaration
@@ -940,68 +327,6 @@ module ts {
}
};
- export interface ReferencePathMatchResult {
- fileReference?: FileReference
- diagnosticMessage?: DiagnosticMessage
- isNoDefaultLib?: boolean
- }
-
- export function getFileReferenceFromReferencePath(comment: string, commentRange: CommentRange): ReferencePathMatchResult {
- var simpleReferenceRegEx = /^\/\/\/\s*/gim;
- if (simpleReferenceRegEx.exec(comment)) {
- if (isNoDefaultLibRegEx.exec(comment)) {
- return {
- isNoDefaultLib: true
- }
- }
- else {
- var matchResult = fullTripleSlashReferencePathRegEx.exec(comment);
- if (matchResult) {
- var start = commentRange.pos;
- var end = commentRange.end;
- return {
- fileReference: {
- pos: start,
- end: end,
- filename: matchResult[3]
- },
- isNoDefaultLib: false
- };
- }
- else {
- return {
- diagnosticMessage: Diagnostics.Invalid_reference_directive_syntax,
- isNoDefaultLib: false
- };
- }
- }
- }
- return undefined;
- }
-
- export function isKeyword(token: SyntaxKind): boolean {
- return SyntaxKind.FirstKeyword <= token && token <= SyntaxKind.LastKeyword;
- }
-
- export function isTrivia(token: SyntaxKind) {
- return SyntaxKind.FirstTriviaToken <= token && token <= SyntaxKind.LastTriviaToken;
- }
-
- export function isModifier(token: SyntaxKind): boolean {
- switch (token) {
- case SyntaxKind.PublicKeyword:
- case SyntaxKind.PrivateKeyword:
- case SyntaxKind.ProtectedKeyword:
- case SyntaxKind.StaticKeyword:
- case SyntaxKind.ExportKeyword:
- case SyntaxKind.DeclareKeyword:
- case SyntaxKind.ConstKeyword:
- return true;
- }
- return false;
- }
-
function modifierToFlag(token: SyntaxKind): NodeFlags {
switch (token) {
case SyntaxKind.StaticKeyword: return NodeFlags.Static;
diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts
new file mode 100644
index 00000000000..15b0bdfc0b2
--- /dev/null
+++ b/src/compiler/utilities.ts
@@ -0,0 +1,732 @@
+///
+
+module ts {
+ export interface ReferencePathMatchResult {
+ fileReference?: FileReference
+ diagnosticMessage?: DiagnosticMessage
+ isNoDefaultLib?: boolean
+ }
+
+ export function getDeclarationOfKind(symbol: Symbol, kind: SyntaxKind): Declaration {
+ var declarations = symbol.declarations;
+ for (var i = 0; i < declarations.length; i++) {
+ var declaration = declarations[i];
+ if (declaration.kind === kind) {
+ return declaration;
+ }
+ }
+
+ return undefined;
+ }
+
+ export interface StringSymbolWriter extends SymbolWriter {
+ string(): string;
+ }
+
+ // Pool writers to avoid needing to allocate them for every symbol we write.
+ var stringWriters: StringSymbolWriter[] = [];
+ export function getSingleLineStringWriter(): StringSymbolWriter {
+ if (stringWriters.length == 0) {
+ var str = "";
+
+ var writeText: (text: string) => void = text => str += text;
+ return {
+ string: () => str,
+ writeKeyword: writeText,
+ writeOperator: writeText,
+ writePunctuation: writeText,
+ writeSpace: writeText,
+ writeStringLiteral: writeText,
+ writeParameter: writeText,
+ writeSymbol: writeText,
+
+ // Completely ignore indentation for string writers. And map newlines to
+ // a single space.
+ writeLine: () => str += " ",
+ increaseIndent: () => { },
+ decreaseIndent: () => { },
+ clear: () => str = "",
+ trackSymbol: () => { }
+ };
+ }
+
+ return stringWriters.pop();
+ }
+
+ export function releaseStringWriter(writer: StringSymbolWriter) {
+ writer.clear()
+ stringWriters.push(writer);
+ }
+
+ export function getFullWidth(node: Node) {
+ return node.end - node.pos;
+ }
+
+ export function hasFlag(val: number, flag: number): boolean {
+ return (val & flag) !== 0;
+ }
+
+ // Returns true if this node contains a parse error anywhere underneath it.
+ export function containsParseError(node: Node): boolean {
+ if (!hasFlag(node.parserContextFlags, ParserContextFlags.HasPropagatedChildContainsErrorFlag)) {
+ // A node is considered to contain a parse error if:
+ // a) the parser explicitly marked that it had an error
+ // b) any of it's children reported that it had an error.
+ var val = hasFlag(node.parserContextFlags, ParserContextFlags.ContainsError) ||
+ forEachChild(node, containsParseError);
+
+ // If so, mark ourselves accordingly.
+ if (val) {
+ node.parserContextFlags |= ParserContextFlags.ContainsError;
+ }
+
+ // Also mark that we've propogated the child information to this node. This way we can
+ // always consult the bit directly on this node without needing to check its children
+ // again.
+ node.parserContextFlags |= ParserContextFlags.HasPropagatedChildContainsErrorFlag;
+ }
+
+ return hasFlag(node.parserContextFlags, ParserContextFlags.ContainsError);
+ }
+
+ export function getSourceFileOfNode(node: Node): SourceFile {
+ while (node && node.kind !== SyntaxKind.SourceFile) node = node.parent;
+ return node;
+ }
+
+ // This is a useful function for debugging purposes.
+ export function nodePosToString(node: Node): string {
+ var file = getSourceFileOfNode(node);
+ var loc = file.getLineAndCharacterFromPosition(node.pos);
+ return file.filename + "(" + loc.line + "," + loc.character + ")";
+ }
+
+ export function getStartPosOfNode(node: Node): number {
+ return node.pos;
+ }
+
+ export function isMissingNode(node: Node) {
+ return node.pos === node.end && node.kind !== SyntaxKind.EndOfFileToken;
+ }
+
+ export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile): number {
+ // With nodes that have no width (i.e. 'Missing' nodes), we actually *don't*
+ // want to skip trivia because this will launch us forward to the next token.
+ if (isMissingNode(node)) {
+ return node.pos;
+ }
+
+ return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos);
+ }
+
+ export function getSourceTextOfNodeFromSourceFile(sourceFile: SourceFile, node: Node): string {
+ if (isMissingNode(node)) {
+ return "";
+ }
+
+ var text = sourceFile.text;
+ return text.substring(skipTrivia(text, node.pos), node.end);
+ }
+
+ export function getTextOfNodeFromSourceText(sourceText: string, node: Node): string {
+ if (isMissingNode(node)) {
+ return "";
+ }
+
+ return sourceText.substring(skipTrivia(sourceText, node.pos), node.end);
+ }
+
+ export function getTextOfNode(node: Node): string {
+ return getSourceTextOfNodeFromSourceFile(getSourceFileOfNode(node), node);
+ }
+
+ // Add an extra underscore to identifiers that start with two underscores to avoid issues with magic names like '__proto__'
+ export function escapeIdentifier(identifier: string): string {
+ return identifier.length >= 2 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ ? "_" + identifier : identifier;
+ }
+
+ // Remove extra underscore from escaped identifier
+ export function unescapeIdentifier(identifier: string): string {
+ return identifier.length >= 3 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ && identifier.charCodeAt(2) === CharacterCodes._ ? identifier.substr(1) : identifier;
+ }
+
+ // Return display name of an identifier
+ // Computed property names will just be emitted as "[]", where is the source
+ // text of the expression in the computed property.
+ export function declarationNameToString(name: DeclarationName) {
+ return getFullWidth(name) === 0 ? "(Missing)" : getTextOfNode(name);
+ }
+
+ export function createDiagnosticForNode(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): Diagnostic {
+ node = getErrorSpanForNode(node);
+ var file = getSourceFileOfNode(node);
+
+ var start = getFullWidth(node) === 0 ? node.pos : skipTrivia(file.text, node.pos);
+ var length = node.end - start;
+
+ return createFileDiagnostic(file, start, length, message, arg0, arg1, arg2);
+ }
+
+ 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, newLine);
+ }
+
+ export function getErrorSpanForNode(node: Node): Node {
+ var errorSpan: Node;
+ switch (node.kind) {
+ // This list is a work in progress. Add missing node kinds to improve their error
+ // spans.
+ case SyntaxKind.VariableDeclaration:
+ case SyntaxKind.BindingElement:
+ case SyntaxKind.ClassDeclaration:
+ case SyntaxKind.InterfaceDeclaration:
+ case SyntaxKind.ModuleDeclaration:
+ case SyntaxKind.EnumDeclaration:
+ case SyntaxKind.EnumMember:
+ errorSpan = (node).name;
+ break;
+ }
+
+ // We now have the ideal error span, but it may be a node that is optional and absent
+ // (e.g. the name of a function expression), in which case errorSpan will be undefined.
+ // Alternatively, it might be required and missing (e.g. the name of a module), in which
+ // case its pos will equal its end (length 0). In either of these cases, we should fall
+ // back to the original node that the error was issued on.
+ return errorSpan && errorSpan.pos < errorSpan.end ? errorSpan : node;
+ }
+
+ export function isExternalModule(file: SourceFile): boolean {
+ return file.externalModuleIndicator !== undefined;
+ }
+
+ export function isDeclarationFile(file: SourceFile): boolean {
+ return (file.flags & NodeFlags.DeclarationFile) !== 0;
+ }
+
+ export function isConstEnumDeclaration(node: Node): boolean {
+ return node.kind === SyntaxKind.EnumDeclaration && isConst(node);
+ }
+
+ export function isConst(node: Node): boolean {
+ return !!(node.flags & NodeFlags.Const);
+ }
+
+ export function isLet(node: Node): boolean {
+ return !!(node.flags & NodeFlags.Let);
+ }
+
+ export function isPrologueDirective(node: Node): boolean {
+ return node.kind === SyntaxKind.ExpressionStatement && (node).expression.kind === SyntaxKind.StringLiteral;
+ }
+
+ export function getLeadingCommentRangesOfNode(node: Node, sourceFileOfNode?: SourceFile) {
+ sourceFileOfNode = sourceFileOfNode || getSourceFileOfNode(node);
+
+ // If parameter/type parameter, the prev token trailing comments are part of this node too
+ if (node.kind === SyntaxKind.Parameter || node.kind === SyntaxKind.TypeParameter) {
+ // e.g. (/** blah */ a, /** blah */ b);
+ return concatenate(getTrailingCommentRanges(sourceFileOfNode.text, node.pos),
+ // e.g.: (
+ // /** blah */ a,
+ // /** blah */ b);
+ getLeadingCommentRanges(sourceFileOfNode.text, node.pos));
+ }
+ else {
+ return getLeadingCommentRanges(sourceFileOfNode.text, node.pos);
+ }
+ }
+
+ export function getJsDocComments(node: Node, sourceFileOfNode: SourceFile) {
+ return filter(getLeadingCommentRangesOfNode(node, sourceFileOfNode), isJsDocComment);
+
+ function isJsDocComment(comment: CommentRange) {
+ // True if the comment starts with '/**' but not if it is '/**/'
+ return sourceFileOfNode.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk &&
+ sourceFileOfNode.text.charCodeAt(comment.pos + 2) === CharacterCodes.asterisk &&
+ sourceFileOfNode.text.charCodeAt(comment.pos + 3) !== CharacterCodes.slash;
+ }
+ }
+
+ export var fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*/
+
+
+ // Warning: This has the same semantics as the forEach family of functions,
+ // in that traversal terminates in the event that 'visitor' supplies a truthy value.
+ export function forEachReturnStatement(body: Block, visitor: (stmt: ReturnStatement) => T): T {
+
+ return traverse(body);
+
+ function traverse(node: Node): T {
+ switch (node.kind) {
+ case SyntaxKind.ReturnStatement:
+ return visitor(node);
+ case SyntaxKind.Block:
+ case SyntaxKind.IfStatement:
+ case SyntaxKind.DoStatement:
+ case SyntaxKind.WhileStatement:
+ case SyntaxKind.ForStatement:
+ case SyntaxKind.ForInStatement:
+ case SyntaxKind.WithStatement:
+ case SyntaxKind.SwitchStatement:
+ case SyntaxKind.CaseClause:
+ case SyntaxKind.DefaultClause:
+ case SyntaxKind.LabeledStatement:
+ case SyntaxKind.TryStatement:
+ case SyntaxKind.TryBlock:
+ case SyntaxKind.CatchClause:
+ case SyntaxKind.FinallyBlock:
+ return forEachChild(node, traverse);
+ }
+ }
+ }
+
+ export function isAnyFunction(node: Node): boolean {
+ if (node) {
+ switch (node.kind) {
+ case SyntaxKind.Constructor:
+ case SyntaxKind.FunctionExpression:
+ case SyntaxKind.FunctionDeclaration:
+ case SyntaxKind.ArrowFunction:
+ case SyntaxKind.MethodDeclaration:
+ case SyntaxKind.MethodSignature:
+ case SyntaxKind.GetAccessor:
+ case SyntaxKind.SetAccessor:
+ case SyntaxKind.CallSignature:
+ case SyntaxKind.ConstructSignature:
+ case SyntaxKind.IndexSignature:
+ case SyntaxKind.FunctionType:
+ case SyntaxKind.ConstructorType:
+ case SyntaxKind.FunctionExpression:
+ case SyntaxKind.ArrowFunction:
+ case SyntaxKind.FunctionDeclaration:
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ export function isFunctionBlock(node: Node) {
+ return node && node.kind === SyntaxKind.Block && isAnyFunction(node.parent);
+ }
+
+ export function isObjectLiteralMethod(node: Node) {
+ return node && node.kind === SyntaxKind.MethodDeclaration && node.parent.kind === SyntaxKind.ObjectLiteralExpression;
+ }
+
+ export function getContainingFunction(node: Node): FunctionLikeDeclaration {
+ while (true) {
+ node = node.parent;
+ if (!node || isAnyFunction(node)) {
+ return node;
+ }
+ }
+ }
+
+ export function getThisContainer(node: Node, includeArrowFunctions: boolean): Node {
+ while (true) {
+ node = node.parent;
+ if (!node) {
+ return undefined;
+ }
+ switch (node.kind) {
+ case SyntaxKind.ArrowFunction:
+ if (!includeArrowFunctions) {
+ continue;
+ }
+ // Fall through
+ case SyntaxKind.FunctionDeclaration:
+ case SyntaxKind.FunctionExpression:
+ case SyntaxKind.ModuleDeclaration:
+ case SyntaxKind.PropertyDeclaration:
+ case SyntaxKind.PropertySignature:
+ case SyntaxKind.MethodDeclaration:
+ case SyntaxKind.MethodSignature:
+ case SyntaxKind.Constructor:
+ case SyntaxKind.GetAccessor:
+ case SyntaxKind.SetAccessor:
+ case SyntaxKind.EnumDeclaration:
+ case SyntaxKind.SourceFile:
+ return node;
+ }
+ }
+ }
+
+ export function getSuperContainer(node: Node): Node {
+ while (true) {
+ node = node.parent;
+ if (!node) {
+ return undefined;
+ }
+ switch (node.kind) {
+ case SyntaxKind.PropertyDeclaration:
+ case SyntaxKind.PropertySignature:
+ case SyntaxKind.MethodDeclaration:
+ case SyntaxKind.MethodSignature:
+ case SyntaxKind.Constructor:
+ case SyntaxKind.GetAccessor:
+ case SyntaxKind.SetAccessor:
+ return node;
+ }
+ }
+ }
+
+ export function getInvokedExpression(node: CallLikeExpression): Expression {
+ if (node.kind === SyntaxKind.TaggedTemplateExpression) {
+ return (node).tag;
+ }
+
+ // Will either be a CallExpression or NewExpression.
+ return (node).expression;
+ }
+
+ export function isExpression(node: Node): boolean {
+ switch (node.kind) {
+ case SyntaxKind.ThisKeyword:
+ case SyntaxKind.SuperKeyword:
+ case SyntaxKind.NullKeyword:
+ case SyntaxKind.TrueKeyword:
+ case SyntaxKind.FalseKeyword:
+ case SyntaxKind.RegularExpressionLiteral:
+ case SyntaxKind.ArrayLiteralExpression:
+ case SyntaxKind.ObjectLiteralExpression:
+ case SyntaxKind.PropertyAccessExpression:
+ case SyntaxKind.ElementAccessExpression:
+ case SyntaxKind.CallExpression:
+ case SyntaxKind.NewExpression:
+ case SyntaxKind.TaggedTemplateExpression:
+ case SyntaxKind.TypeAssertionExpression:
+ case SyntaxKind.ParenthesizedExpression:
+ case SyntaxKind.FunctionExpression:
+ case SyntaxKind.ArrowFunction:
+ case SyntaxKind.VoidExpression:
+ case SyntaxKind.DeleteExpression:
+ case SyntaxKind.TypeOfExpression:
+ case SyntaxKind.PrefixUnaryExpression:
+ case SyntaxKind.PostfixUnaryExpression:
+ case SyntaxKind.BinaryExpression:
+ case SyntaxKind.ConditionalExpression:
+ case SyntaxKind.TemplateExpression:
+ case SyntaxKind.NoSubstitutionTemplateLiteral:
+ case SyntaxKind.OmittedExpression:
+ return true;
+ case SyntaxKind.QualifiedName:
+ while (node.parent.kind === SyntaxKind.QualifiedName) {
+ node = node.parent;
+ }
+
+ return node.parent.kind === SyntaxKind.TypeQuery;
+ case SyntaxKind.Identifier:
+ if (node.parent.kind === SyntaxKind.TypeQuery) {
+ return true;
+ }
+ // fall through
+ case SyntaxKind.NumericLiteral:
+ case SyntaxKind.StringLiteral:
+ var parent = node.parent;
+ switch (parent.kind) {
+ case SyntaxKind.VariableDeclaration:
+ case SyntaxKind.Parameter:
+ case SyntaxKind.PropertyDeclaration:
+ case SyntaxKind.PropertySignature:
+ case SyntaxKind.EnumMember:
+ case SyntaxKind.PropertyAssignment:
+ case SyntaxKind.BindingElement:
+ return (parent).initializer === node;
+ case SyntaxKind.ExpressionStatement:
+ case SyntaxKind.IfStatement:
+ case SyntaxKind.DoStatement:
+ case SyntaxKind.WhileStatement:
+ case SyntaxKind.ReturnStatement:
+ case SyntaxKind.WithStatement:
+ case SyntaxKind.SwitchStatement:
+ case SyntaxKind.CaseClause:
+ case SyntaxKind.ThrowStatement:
+ case SyntaxKind.SwitchStatement:
+ return (parent).expression === node;
+ case SyntaxKind.ForStatement:
+ return (parent).initializer === node ||
+ (parent).condition === node ||
+ (parent).iterator === node;
+ case SyntaxKind.ForInStatement:
+ return (parent).variable === node ||
+ (parent).expression === node;
+ case SyntaxKind.TypeAssertionExpression:
+ return node === (parent).expression;
+ case SyntaxKind.TemplateSpan:
+ return node === (parent).expression;
+ default:
+ if (isExpression(parent)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ export function isExternalModuleImportDeclaration(node: Node) {
+ return node.kind === SyntaxKind.ImportDeclaration && (node).moduleReference.kind === SyntaxKind.ExternalModuleReference;
+ }
+
+ export function getExternalModuleImportDeclarationExpression(node: Node) {
+ Debug.assert(isExternalModuleImportDeclaration(node));
+ return ((node).moduleReference).expression;
+ }
+
+ export function isInternalModuleImportDeclaration(node: Node) {
+ return node.kind === SyntaxKind.ImportDeclaration && (node).moduleReference.kind !== SyntaxKind.ExternalModuleReference;
+ }
+
+ export function hasDotDotDotToken(node: Node) {
+ return node && node.kind === SyntaxKind.Parameter && (node).dotDotDotToken !== undefined;
+ }
+
+ export function hasQuestionToken(node: Node) {
+ if (node) {
+ switch (node.kind) {
+ case SyntaxKind.Parameter:
+ return (node).questionToken !== undefined;
+ case SyntaxKind.MethodDeclaration:
+ case SyntaxKind.MethodSignature:
+ return (node).questionToken !== undefined;
+ case SyntaxKind.ShorthandPropertyAssignment:
+ case SyntaxKind.PropertyAssignment:
+ case SyntaxKind.PropertyDeclaration:
+ case SyntaxKind.PropertySignature:
+ return (node).questionToken !== undefined;
+ }
+ }
+
+ return false;
+ }
+
+ export function hasRestParameters(s: SignatureDeclaration): boolean {
+ return s.parameters.length > 0 && s.parameters[s.parameters.length - 1].dotDotDotToken !== undefined;
+ }
+
+ export function isLiteralKind(kind: SyntaxKind): boolean {
+ return SyntaxKind.FirstLiteralToken <= kind && kind <= SyntaxKind.LastLiteralToken;
+ }
+
+ export function isTextualLiteralKind(kind: SyntaxKind): boolean {
+ return kind === SyntaxKind.StringLiteral || kind === SyntaxKind.NoSubstitutionTemplateLiteral;
+ }
+
+ export function isTemplateLiteralKind(kind: SyntaxKind): boolean {
+ return SyntaxKind.FirstTemplateToken <= kind && kind <= SyntaxKind.LastTemplateToken;
+ }
+
+ export function isBindingPattern(node: Node) {
+ return node.kind === SyntaxKind.ArrayBindingPattern || node.kind === SyntaxKind.ObjectBindingPattern;
+ }
+
+ export function isInAmbientContext(node: Node): boolean {
+ while (node) {
+ if (node.flags & (NodeFlags.Ambient | NodeFlags.DeclarationFile)) return true;
+ node = node.parent;
+ }
+ return false;
+ }
+
+ export function isDeclaration(node: Node): boolean {
+ switch (node.kind) {
+ case SyntaxKind.TypeParameter:
+ case SyntaxKind.Parameter:
+ case SyntaxKind.VariableDeclaration:
+ case SyntaxKind.BindingElement:
+ case SyntaxKind.PropertyDeclaration:
+ case SyntaxKind.PropertySignature:
+ case SyntaxKind.PropertyAssignment:
+ case SyntaxKind.ShorthandPropertyAssignment:
+ case SyntaxKind.EnumMember:
+ case SyntaxKind.MethodDeclaration:
+ case SyntaxKind.MethodSignature:
+ case SyntaxKind.FunctionDeclaration:
+ case SyntaxKind.GetAccessor:
+ case SyntaxKind.SetAccessor:
+ case SyntaxKind.Constructor:
+ case SyntaxKind.ClassDeclaration:
+ case SyntaxKind.InterfaceDeclaration:
+ case SyntaxKind.TypeAliasDeclaration:
+ case SyntaxKind.EnumDeclaration:
+ case SyntaxKind.ModuleDeclaration:
+ case SyntaxKind.ImportDeclaration:
+ return true;
+ }
+ return false;
+ }
+
+ export function isStatement(n: Node): boolean {
+ switch (n.kind) {
+ case SyntaxKind.BreakStatement:
+ case SyntaxKind.ContinueStatement:
+ case SyntaxKind.DebuggerStatement:
+ case SyntaxKind.DoStatement:
+ case SyntaxKind.ExpressionStatement:
+ case SyntaxKind.EmptyStatement:
+ case SyntaxKind.ForInStatement:
+ case SyntaxKind.ForStatement:
+ case SyntaxKind.IfStatement:
+ case SyntaxKind.LabeledStatement:
+ case SyntaxKind.ReturnStatement:
+ case SyntaxKind.SwitchStatement:
+ case SyntaxKind.ThrowKeyword:
+ case SyntaxKind.TryStatement:
+ case SyntaxKind.VariableStatement:
+ case SyntaxKind.WhileStatement:
+ case SyntaxKind.WithStatement:
+ case SyntaxKind.ExportAssignment:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ // True if the given identifier, string literal, or number literal is the name of a declaration node
+ export function isDeclarationOrFunctionExpressionOrCatchVariableName(name: Node): boolean {
+ if (name.kind !== SyntaxKind.Identifier && name.kind !== SyntaxKind.StringLiteral && name.kind !== SyntaxKind.NumericLiteral) {
+ return false;
+ }
+
+ var parent = name.parent;
+ if (isDeclaration(parent) || parent.kind === SyntaxKind.FunctionExpression) {
+ return (parent).name === name;
+ }
+
+ if (parent.kind === SyntaxKind.CatchClause) {
+ return (parent).name === name;
+ }
+
+ return false;
+ }
+
+ export function getClassBaseTypeNode(node: ClassDeclaration) {
+ var heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ExtendsKeyword);
+ return heritageClause && heritageClause.types.length > 0 ? heritageClause.types[0] : undefined;
+ }
+
+ export function getClassImplementedTypeNodes(node: ClassDeclaration) {
+ var heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ImplementsKeyword);
+ return heritageClause ? heritageClause.types : undefined;
+ }
+
+ export function getInterfaceBaseTypeNodes(node: InterfaceDeclaration) {
+ var heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ExtendsKeyword);
+ return heritageClause ? heritageClause.types : undefined;
+ }
+
+ export function getHeritageClause(clauses: NodeArray, kind: SyntaxKind) {
+ if (clauses) {
+ for (var i = 0, n = clauses.length; i < n; i++) {
+ if (clauses[i].token === kind) {
+ return clauses[i];
+ }
+ }
+ }
+
+ return undefined;
+ }
+
+ export function tryResolveScriptReference(program: Program, sourceFile: SourceFile, reference: FileReference) {
+ if (!program.getCompilerOptions().noResolve) {
+ var referenceFileName = isRootedDiskPath(reference.filename) ? reference.filename : combinePaths(getDirectoryPath(sourceFile.filename), reference.filename);
+ referenceFileName = getNormalizedAbsolutePath(referenceFileName, program.getCompilerHost().getCurrentDirectory());
+ return program.getSourceFile(referenceFileName);
+ }
+ }
+
+ export function getAncestor(node: Node, kind: SyntaxKind): Node {
+ switch (kind) {
+ // special-cases that can be come first
+ case SyntaxKind.ClassDeclaration:
+ while (node) {
+ switch (node.kind) {
+ case SyntaxKind.ClassDeclaration:
+ return node;
+ case SyntaxKind.EnumDeclaration:
+ case SyntaxKind.InterfaceDeclaration:
+ case SyntaxKind.TypeAliasDeclaration:
+ case SyntaxKind.ModuleDeclaration:
+ case SyntaxKind.ImportDeclaration:
+ // early exit cases - declarations cannot be nested in classes
+ return undefined;
+ default:
+ node = node.parent;
+ continue;
+ }
+ }
+ break;
+ default:
+ while (node) {
+ if (node.kind === kind) {
+ return node;
+ }
+ node = node.parent;
+ }
+ break;
+ }
+
+ return undefined;
+ }
+
+ export function getFileReferenceFromReferencePath(comment: string, commentRange: CommentRange): ReferencePathMatchResult {
+ var simpleReferenceRegEx = /^\/\/\/\s*/gim;
+ if (simpleReferenceRegEx.exec(comment)) {
+ if (isNoDefaultLibRegEx.exec(comment)) {
+ return {
+ isNoDefaultLib: true
+ }
+ }
+ else {
+ var matchResult = fullTripleSlashReferencePathRegEx.exec(comment);
+ if (matchResult) {
+ var start = commentRange.pos;
+ var end = commentRange.end;
+ return {
+ fileReference: {
+ pos: start,
+ end: end,
+ filename: matchResult[3]
+ },
+ isNoDefaultLib: false
+ };
+ }
+ else {
+ return {
+ diagnosticMessage: Diagnostics.Invalid_reference_directive_syntax,
+ isNoDefaultLib: false
+ };
+ }
+ }
+ }
+ return undefined;
+ }
+
+ export function isKeyword(token: SyntaxKind): boolean {
+ return SyntaxKind.FirstKeyword <= token && token <= SyntaxKind.LastKeyword;
+ }
+
+ export function isTrivia(token: SyntaxKind) {
+ return SyntaxKind.FirstTriviaToken <= token && token <= SyntaxKind.LastTriviaToken;
+ }
+
+ export function isModifier(token: SyntaxKind): boolean {
+ switch (token) {
+ case SyntaxKind.PublicKeyword:
+ case SyntaxKind.PrivateKeyword:
+ case SyntaxKind.ProtectedKeyword:
+ case SyntaxKind.StaticKeyword:
+ case SyntaxKind.ExportKeyword:
+ case SyntaxKind.DeclareKeyword:
+ case SyntaxKind.ConstKeyword:
+ return true;
+ }
+ return false;
+ }
+
+}
\ No newline at end of file
diff --git a/src/services/services.ts b/src/services/services.ts
index 66108bb29bb..cdf4c55881a 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -1662,6 +1662,10 @@ module ts {
owners: string[];
}
+ export interface DisplayPartsSymbolWriter extends SymbolWriter {
+ displayParts(): SymbolDisplayPart[];
+ }
+
export function displayPartsToString(displayParts: SymbolDisplayPart[]) {
if (displayParts) {
return map(displayParts, displayPart => displayPart.text).join("");
@@ -1670,100 +1674,6 @@ module ts {
return "";
}
- export interface DisplayPartsSymbolWriter extends SymbolWriter {
- displayParts(): SymbolDisplayPart[];
- }
-
- var displayPartWriter = getDisplayPartWriter();
- function getDisplayPartWriter(): DisplayPartsSymbolWriter {
- var displayParts: SymbolDisplayPart[];
- var lineStart: boolean;
- var indent: number;
-
- resetWriter();
- return {
- displayParts: () => displayParts,
- writeKeyword: text => writeKind(text, SymbolDisplayPartKind.keyword),
- writeOperator: text => writeKind(text, SymbolDisplayPartKind.operator),
- writePunctuation: text => writeKind(text, SymbolDisplayPartKind.punctuation),
- writeSpace: text => writeKind(text, SymbolDisplayPartKind.space),
- writeStringLiteral: text => writeKind(text, SymbolDisplayPartKind.stringLiteral),
- writeParameter: text => writeKind(text, SymbolDisplayPartKind.parameterName),
- writeSymbol,
- writeLine,
- increaseIndent: () => { indent++; },
- decreaseIndent: () => { indent--; },
- clear: resetWriter,
- trackSymbol: () => { }
- };
-
- function writeIndent() {
- if (lineStart) {
- var indentString = getIndentString(indent);
- if (indentString) {
- displayParts.push(displayPart(indentString, SymbolDisplayPartKind.space));
- }
- lineStart = false;
- }
- }
-
- function writeKind(text: string, kind: SymbolDisplayPartKind) {
- writeIndent();
- displayParts.push(displayPart(text, kind));
- }
-
- function writeSymbol(text: string, symbol: Symbol) {
- writeIndent();
- displayParts.push(symbolPart(text, symbol));
- }
-
- function writeLine() {
- displayParts.push(lineBreakPart());
- lineStart = true;
- }
-
- function resetWriter() {
- displayParts = []
- lineStart = true;
- indent = 0;
- }
- }
-
- function displayPart(text: string, kind: SymbolDisplayPartKind, symbol?: Symbol): SymbolDisplayPart {
- return {
- text: text,
- kind: SymbolDisplayPartKind[kind]
- };
- }
-
- export function spacePart() {
- return displayPart(" ", SymbolDisplayPartKind.space);
- }
-
- export function keywordPart(kind: SyntaxKind) {
- return displayPart(tokenToString(kind), SymbolDisplayPartKind.keyword);
- }
-
- export function punctuationPart(kind: SyntaxKind) {
- return displayPart(tokenToString(kind), SymbolDisplayPartKind.punctuation);
- }
-
- export function operatorPart(kind: SyntaxKind) {
- return displayPart(tokenToString(kind), SymbolDisplayPartKind.operator);
- }
-
- export function textPart(text: string) {
- return displayPart(text, SymbolDisplayPartKind.text);
- }
-
- export function lineBreakPart() {
- return displayPart("\n", SymbolDisplayPartKind.lineBreak);
- }
-
- function isFirstDeclarationOfSymbolParameter(symbol: Symbol) {
- return symbol.declarations && symbol.declarations.length > 0 && symbol.declarations[0].kind === SyntaxKind.Parameter;
- }
-
function isLocalVariableOrFunction(symbol: Symbol) {
if (symbol.parent) {
return false; // This is exported symbol
@@ -1792,59 +1702,6 @@ module ts {
});
}
- export function symbolPart(text: string, symbol: Symbol) {
- return displayPart(text, displayPartKind(symbol), symbol);
-
- function displayPartKind(symbol: Symbol): SymbolDisplayPartKind {
- var flags = symbol.flags;
-
- if (flags & SymbolFlags.Variable) {
- return isFirstDeclarationOfSymbolParameter(symbol) ? SymbolDisplayPartKind.parameterName : SymbolDisplayPartKind.localName;
- }
- else if (flags & SymbolFlags.Property) { return SymbolDisplayPartKind.propertyName; }
- else if (flags & SymbolFlags.GetAccessor) { return SymbolDisplayPartKind.propertyName; }
- else if (flags & SymbolFlags.SetAccessor) { return SymbolDisplayPartKind.propertyName; }
- else if (flags & SymbolFlags.EnumMember) { return SymbolDisplayPartKind.enumMemberName; }
- else if (flags & SymbolFlags.Function) { return SymbolDisplayPartKind.functionName; }
- else if (flags & SymbolFlags.Class) { return SymbolDisplayPartKind.className; }
- else if (flags & SymbolFlags.Interface) { return SymbolDisplayPartKind.interfaceName; }
- else if (flags & SymbolFlags.Enum) { return SymbolDisplayPartKind.enumName; }
- else if (flags & SymbolFlags.Module) { return SymbolDisplayPartKind.moduleName; }
- else if (flags & SymbolFlags.Method) { return SymbolDisplayPartKind.methodName; }
- else if (flags & SymbolFlags.TypeParameter) { return SymbolDisplayPartKind.typeParameterName; }
- else if (flags & SymbolFlags.TypeAlias) { return SymbolDisplayPartKind.aliasName; }
- else if (flags & SymbolFlags.Import) { return SymbolDisplayPartKind.aliasName; }
-
-
- return SymbolDisplayPartKind.text;
- }
- }
-
- export function mapToDisplayParts(writeDisplayParts: (writer: DisplayPartsSymbolWriter) => void): SymbolDisplayPart[] {
- writeDisplayParts(displayPartWriter);
- var result = displayPartWriter.displayParts();
- displayPartWriter.clear();
- return result;
- }
-
- export function typeToDisplayParts(typechecker: TypeChecker, type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[] {
- return mapToDisplayParts(writer => {
- typechecker.getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags);
- });
- }
-
- export function symbolToDisplayParts(typeChecker: TypeChecker, symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): SymbolDisplayPart[] {
- return mapToDisplayParts(writer => {
- typeChecker.getSymbolDisplayBuilder().buildSymbolDisplay(symbol, writer, enclosingDeclaration, meaning, flags);
- });
- }
-
- function signatureToDisplayParts(typechecker: TypeChecker, signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[]{
- return mapToDisplayParts(writer => {
- typechecker.getSymbolDisplayBuilder().buildSignatureDisplay(signature, writer, enclosingDeclaration, flags);
- });
- }
-
export function getDefaultCompilerOptions(): CompilerOptions {
// Set "ScriptTarget.Latest" target by default for language service
return {
@@ -1853,20 +1710,6 @@ module ts {
};
}
- export function compareDataObjects(dst: any, src: any): boolean {
- for (var e in dst) {
- if (typeof dst[e] === "object") {
- if (!compareDataObjects(dst[e], src[e]))
- return false;
- }
- else if (typeof dst[e] !== "function") {
- if (dst[e] !== src[e])
- return false;
- }
- }
- return true;
- }
-
export class OperationCanceledException { }
export class CancellationTokenObject {
@@ -2205,20 +2048,6 @@ module ts {
}
/// Helpers
- export function getNodeModifiers(node: Node): string {
- var flags = node.flags;
- var result: string[] = [];
-
- if (flags & NodeFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier);
- if (flags & NodeFlags.Protected) result.push(ScriptElementKindModifier.protectedMemberModifier);
- if (flags & NodeFlags.Public) result.push(ScriptElementKindModifier.publicMemberModifier);
- if (flags & NodeFlags.Static) result.push(ScriptElementKindModifier.staticModifier);
- if (flags & NodeFlags.Export) result.push(ScriptElementKindModifier.exportedModifier);
- if (isInAmbientContext(node)) result.push(ScriptElementKindModifier.ambientModifier);
-
- return result.length > 0 ? result.join(',') : ScriptElementKindModifier.none;
- }
-
function getTargetLabel(referenceNode: Node, labelName: string): Identifier {
while (referenceNode) {
if (referenceNode.kind === SyntaxKind.LabeledStatement && (referenceNode).label.text === labelName) {
diff --git a/src/services/utilities.ts b/src/services/utilities.ts
index 32551d9737b..146ea141d76 100644
--- a/src/services/utilities.ts
+++ b/src/services/utilities.ts
@@ -270,7 +270,21 @@ module ts {
return n.getWidth() !== 0;
}
- export function getTypeArgumentOrTypeParameterList(node: Node): NodeArray {
+ export function getNodeModifiers(node: Node): string {
+ var flags = node.flags;
+ var result: string[] = [];
+
+ if (flags & NodeFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier);
+ if (flags & NodeFlags.Protected) result.push(ScriptElementKindModifier.protectedMemberModifier);
+ if (flags & NodeFlags.Public) result.push(ScriptElementKindModifier.publicMemberModifier);
+ if (flags & NodeFlags.Static) result.push(ScriptElementKindModifier.staticModifier);
+ if (flags & NodeFlags.Export) result.push(ScriptElementKindModifier.exportedModifier);
+ if (isInAmbientContext(node)) result.push(ScriptElementKindModifier.ambientModifier);
+
+ return result.length > 0 ? result.join(',') : ScriptElementKindModifier.none;
+ }
+
+ export function getTypeArgumentOrTypeParameterList(node: Node): NodeArray {
if (node.kind === SyntaxKind.TypeReference || node.kind === SyntaxKind.CallExpression) {
return (node).typeArguments;
}
@@ -306,4 +320,166 @@ module ts {
return isTemplateLiteralKind(node.kind)
&& (node.getStart() < position && position < node.getEnd()) || (!!node.isUnterminated && position === node.getEnd());
}
+
+ export function compareDataObjects(dst: any, src: any): boolean {
+ for (var e in dst) {
+ if (typeof dst[e] === "object") {
+ if (!compareDataObjects(dst[e], src[e])) {
+ return false;
+ }
+ }
+ else if (typeof dst[e] !== "function") {
+ if (dst[e] !== src[e]) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
+
+// Display-part writer helpers
+module ts {
+ export function isFirstDeclarationOfSymbolParameter(symbol: Symbol) {
+ return symbol.declarations && symbol.declarations.length > 0 && symbol.declarations[0].kind === SyntaxKind.Parameter;
+ }
+
+ var displayPartWriter = getDisplayPartWriter();
+ function getDisplayPartWriter(): DisplayPartsSymbolWriter {
+ var displayParts: SymbolDisplayPart[];
+ var lineStart: boolean;
+ var indent: number;
+
+ resetWriter();
+ return {
+ displayParts: () => displayParts,
+ writeKeyword: text => writeKind(text, SymbolDisplayPartKind.keyword),
+ writeOperator: text => writeKind(text, SymbolDisplayPartKind.operator),
+ writePunctuation: text => writeKind(text, SymbolDisplayPartKind.punctuation),
+ writeSpace: text => writeKind(text, SymbolDisplayPartKind.space),
+ writeStringLiteral: text => writeKind(text, SymbolDisplayPartKind.stringLiteral),
+ writeParameter: text => writeKind(text, SymbolDisplayPartKind.parameterName),
+ writeSymbol,
+ writeLine,
+ increaseIndent: () => { indent++; },
+ decreaseIndent: () => { indent--; },
+ clear: resetWriter,
+ trackSymbol: () => { }
+ };
+
+ function writeIndent() {
+ if (lineStart) {
+ var indentString = getIndentString(indent);
+ if (indentString) {
+ displayParts.push(displayPart(indentString, SymbolDisplayPartKind.space));
+ }
+ lineStart = false;
+ }
+ }
+
+ function writeKind(text: string, kind: SymbolDisplayPartKind) {
+ writeIndent();
+ displayParts.push(displayPart(text, kind));
+ }
+
+ function writeSymbol(text: string, symbol: Symbol) {
+ writeIndent();
+ displayParts.push(symbolPart(text, symbol));
+ }
+
+ function writeLine() {
+ displayParts.push(lineBreakPart());
+ lineStart = true;
+ }
+
+ function resetWriter() {
+ displayParts = []
+ lineStart = true;
+ indent = 0;
+ }
+ }
+
+ export function symbolPart(text: string, symbol: Symbol) {
+ return displayPart(text, displayPartKind(symbol), symbol);
+
+ function displayPartKind(symbol: Symbol): SymbolDisplayPartKind {
+ var flags = symbol.flags;
+
+ if (flags & SymbolFlags.Variable) {
+ return isFirstDeclarationOfSymbolParameter(symbol) ? SymbolDisplayPartKind.parameterName : SymbolDisplayPartKind.localName;
+ }
+ else if (flags & SymbolFlags.Property) { return SymbolDisplayPartKind.propertyName; }
+ else if (flags & SymbolFlags.GetAccessor) { return SymbolDisplayPartKind.propertyName; }
+ else if (flags & SymbolFlags.SetAccessor) { return SymbolDisplayPartKind.propertyName; }
+ else if (flags & SymbolFlags.EnumMember) { return SymbolDisplayPartKind.enumMemberName; }
+ else if (flags & SymbolFlags.Function) { return SymbolDisplayPartKind.functionName; }
+ else if (flags & SymbolFlags.Class) { return SymbolDisplayPartKind.className; }
+ else if (flags & SymbolFlags.Interface) { return SymbolDisplayPartKind.interfaceName; }
+ else if (flags & SymbolFlags.Enum) { return SymbolDisplayPartKind.enumName; }
+ else if (flags & SymbolFlags.Module) { return SymbolDisplayPartKind.moduleName; }
+ else if (flags & SymbolFlags.Method) { return SymbolDisplayPartKind.methodName; }
+ else if (flags & SymbolFlags.TypeParameter) { return SymbolDisplayPartKind.typeParameterName; }
+ else if (flags & SymbolFlags.TypeAlias) { return SymbolDisplayPartKind.aliasName; }
+ else if (flags & SymbolFlags.Import) { return SymbolDisplayPartKind.aliasName; }
+
+
+ return SymbolDisplayPartKind.text;
+ }
+ }
+
+ export function displayPart(text: string, kind: SymbolDisplayPartKind, symbol?: Symbol): SymbolDisplayPart {
+ return {
+ text: text,
+ kind: SymbolDisplayPartKind[kind]
+ };
+ }
+
+ export function spacePart() {
+ return displayPart(" ", SymbolDisplayPartKind.space);
+ }
+
+ export function keywordPart(kind: SyntaxKind) {
+ return displayPart(tokenToString(kind), SymbolDisplayPartKind.keyword);
+ }
+
+ export function punctuationPart(kind: SyntaxKind) {
+ return displayPart(tokenToString(kind), SymbolDisplayPartKind.punctuation);
+ }
+
+ export function operatorPart(kind: SyntaxKind) {
+ return displayPart(tokenToString(kind), SymbolDisplayPartKind.operator);
+ }
+
+ export function textPart(text: string) {
+ return displayPart(text, SymbolDisplayPartKind.text);
+ }
+
+ export function lineBreakPart() {
+ return displayPart("\n", SymbolDisplayPartKind.lineBreak);
+ }
+
+ export function mapToDisplayParts(writeDisplayParts: (writer: DisplayPartsSymbolWriter) => void): SymbolDisplayPart[] {
+ writeDisplayParts(displayPartWriter);
+ var result = displayPartWriter.displayParts();
+ displayPartWriter.clear();
+ return result;
+ }
+
+ export function typeToDisplayParts(typechecker: TypeChecker, type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[] {
+ return mapToDisplayParts(writer => {
+ typechecker.getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags);
+ });
+ }
+
+ export function symbolToDisplayParts(typeChecker: TypeChecker, symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): SymbolDisplayPart[] {
+ return mapToDisplayParts(writer => {
+ typeChecker.getSymbolDisplayBuilder().buildSymbolDisplay(symbol, writer, enclosingDeclaration, meaning, flags);
+ });
+ }
+
+ export function signatureToDisplayParts(typechecker: TypeChecker, signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags): SymbolDisplayPart[] {
+ return mapToDisplayParts(writer => {
+ typechecker.getSymbolDisplayBuilder().buildSignatureDisplay(signature, writer, enclosingDeclaration, flags);
+ });
+ }
}
\ No newline at end of file