diff --git a/.gitignore b/.gitignore
index 8e2c10d7b32..57e8804d7c3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,3 +43,4 @@ scripts/word2md.js
scripts/ior.js
scripts/*.js.map
coverage/
+internal/
diff --git a/scripts/bisect-test.ts b/scripts/bisect-test.ts
new file mode 100644
index 00000000000..93a516bc899
--- /dev/null
+++ b/scripts/bisect-test.ts
@@ -0,0 +1,56 @@
+///
+
+import cp = require('child_process');
+import fs = require('fs');
+
+// Slice off 'node bisect-test.js' from the commandline args
+var args = process.argv.slice(2);
+
+function tsc(tscArgs: string, onExit: (exitCode: number) => void) {
+ var tsc = cp.exec('node built/local/tsc.js ' + tscArgs,() => void 0);
+ tsc.on('close', tscExitCode => {
+ onExit(tscExitCode);
+ });
+}
+
+var jake = cp.exec('jake clean local', () => void 0);
+jake.on('close', jakeExitCode => {
+ if (jakeExitCode === 0) {
+ // See what we're being asked to do
+ if (args[1] === 'compiles' || args[1] === '!compiles') {
+ tsc(args[0], tscExitCode => {
+ if ((tscExitCode === 0) === (args[1] === 'compiles')) {
+ console.log('Good');
+ process.exit(0); // Good
+ } else {
+ console.log('Bad');
+ process.exit(1); // Bad
+ }
+ });
+ } else if (args[1] === 'emits' || args[1] === '!emits') {
+ tsc(args[0], tscExitCode => {
+ fs.readFile(args[2], 'utf-8', (err, data) => {
+ var doesContains = data.indexOf(args[3]) >= 0;
+ if (doesContains === (args[1] === 'emits')) {
+ console.log('Good');
+ process.exit(0); // Good
+ } else {
+ console.log('Bad');
+ process.exit(1); // Bad
+ }
+ });
+ });
+ } else {
+ console.log('Unknown command line arguments.');
+ console.log('Usage (compile errors): git bisect run scripts\bisect.js "foo.ts --module amd" compiles');
+ console.log('Usage (emit check): git bisect run scripts\bisect.js bar.ts emits bar.js "_this = this"');
+ // Aborts the 'git bisect run' process
+ process.exit(-1);
+ }
+ } else {
+ // Compiler build failed; skip this commit
+ console.log('Skip');
+ process.exit(125); // bisect skip
+ }
+});
+
\ No newline at end of file
diff --git a/scripts/bisect.cmd b/scripts/bisect.cmd
new file mode 100644
index 00000000000..148722665d4
--- /dev/null
+++ b/scripts/bisect.cmd
@@ -0,0 +1,30 @@
+echo off
+IF NOT EXIST scripts\bisect.cmd GOTO :wrongdir
+IF "%1" == "" GOTO :usage
+IF "%1" == "GO" GOTO :run
+GOTO :copy
+
+:usage
+echo Usage: bisect GoodCommit BadCommit test.ts compiles
+echo Usage: bisect GoodCommit BadCommit test.ts emits test.js "var x = 3"
+GOTO :eof
+
+:copy
+copy scripts\bisect.cmd scripts\bisect-fresh.cmd
+scripts\bisect-fresh GO %*
+GOTO :eof
+
+:run
+call jake local
+node built/local/tsc.js scripts/bisect-test.ts --module commonjs
+git bisect start %2 %3
+git bisect run node scripts/bisect-test.js %4 %5 %6 %7
+del scripts\bisect-test.js
+del scripts\bisect-fresh.cmd
+GOTO :eof
+
+:wrongdir
+@echo Run this file from the repo folder, not the scripts folder
+GOTO :eof
+
+:eof
\ No newline at end of file
diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts
index 145cdb5dc70..fe52e26ddd1 100644
--- a/src/compiler/binder.ts
+++ b/src/compiler/binder.ts
@@ -50,12 +50,13 @@ module ts {
}
/**
- * Returns false if any of the following are true:
- * 1. declaration has no name
- * 2. declaration has a literal name (not computed)
- * 3. declaration has a computed property name that is a known symbol
+ * A declaration has a dynamic name if both of the following are true:
+ * 1. The declaration has a computed property name
+ * 2. The computed name is *not* expressed as Symbol., where name
+ * is a property of the Symbol constructor that denotes a built in
+ * Symbol.
*/
- export function hasComputedNameButNotSymbol(declaration: Declaration): boolean {
+ export function hasDynamicName(declaration: Declaration): boolean {
return declaration.name && declaration.name.kind === SyntaxKind.ComputedPropertyName;
}
@@ -96,7 +97,7 @@ module ts {
if (node.kind === SyntaxKind.ModuleDeclaration && node.name.kind === SyntaxKind.StringLiteral) {
return '"' + (node.name).text + '"';
}
- Debug.assert(!hasComputedNameButNotSymbol(node));
+ Debug.assert(!hasDynamicName(node));
return (node.name).text;
}
switch (node.kind) {
@@ -118,11 +119,7 @@ module ts {
}
function declareSymbol(symbols: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol {
- // Nodes with computed property names will not get symbols, because the type checker
- // does not make properties for them.
- if (hasComputedNameButNotSymbol(node)) {
- return undefined;
- }
+ Debug.assert(!hasDynamicName(node));
var name = getDeclarationName(node);
if (name !== undefined) {
@@ -395,14 +392,14 @@ module ts {
break;
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
- bindDeclaration(node, SymbolFlags.Property | ((node).questionToken ? SymbolFlags.Optional : 0), SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false);
+ bindPropertyOrMethodOrAccessor(node, SymbolFlags.Property | ((node).questionToken ? SymbolFlags.Optional : 0), SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.PropertyAssignment:
case SyntaxKind.ShorthandPropertyAssignment:
- bindDeclaration(node, SymbolFlags.Property, SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false);
+ bindPropertyOrMethodOrAccessor(node, SymbolFlags.Property, SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.EnumMember:
- bindDeclaration(node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes, /*isBlockScopeContainer*/ false);
+ bindPropertyOrMethodOrAccessor(node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes, /*isBlockScopeContainer*/ false);
break;
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
@@ -415,7 +412,7 @@ module ts {
// as other properties in the object literal. So we use SymbolFlags.PropertyExcludes
// so that it will conflict with any other object literal members with the same
// name.
- bindDeclaration(node, SymbolFlags.Method | ((node).questionToken ? SymbolFlags.Optional : 0),
+ bindPropertyOrMethodOrAccessor(node, SymbolFlags.Method | ((node).questionToken ? SymbolFlags.Optional : 0),
isObjectLiteralMethod(node) ? SymbolFlags.PropertyExcludes : SymbolFlags.MethodExcludes, /*isBlockScopeContainer*/ true);
break;
case SyntaxKind.FunctionDeclaration:
@@ -425,10 +422,10 @@ module ts {
bindDeclaration(node, SymbolFlags.Constructor, /*symbolExcludes:*/ 0, /*isBlockScopeContainer:*/ true);
break;
case SyntaxKind.GetAccessor:
- bindDeclaration(node, SymbolFlags.GetAccessor, SymbolFlags.GetAccessorExcludes, /*isBlockScopeContainer*/ true);
+ bindPropertyOrMethodOrAccessor(node, SymbolFlags.GetAccessor, SymbolFlags.GetAccessorExcludes, /*isBlockScopeContainer*/ true);
break;
case SyntaxKind.SetAccessor:
- bindDeclaration(node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes, /*isBlockScopeContainer*/ true);
+ bindPropertyOrMethodOrAccessor(node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes, /*isBlockScopeContainer*/ true);
break;
case SyntaxKind.FunctionType:
@@ -510,5 +507,14 @@ module ts {
declareSymbol(classDeclaration.symbol.members, classDeclaration.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
}
}
+
+ function bindPropertyOrMethodOrAccessor(node: Declaration, symbolKind: SymbolFlags, symbolExcludes: SymbolFlags, isBlockScopeContainer: boolean) {
+ if (hasDynamicName(node)) {
+ bindAnonymousDeclaration(node, symbolKind, "__computed", isBlockScopeContainer);
+ }
+ else {
+ bindDeclaration(node, symbolKind, symbolExcludes, isBlockScopeContainer);
+ }
+ }
}
}
diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 1e84c78fce1..ed89032b781 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -66,8 +66,8 @@ module ts {
var numberType = createIntrinsicType(TypeFlags.Number, "number");
var booleanType = createIntrinsicType(TypeFlags.Boolean, "boolean");
var voidType = createIntrinsicType(TypeFlags.Void, "void");
- var undefinedType = createIntrinsicType(TypeFlags.Undefined | TypeFlags.Unwidened, "undefined");
- var nullType = createIntrinsicType(TypeFlags.Null | TypeFlags.Unwidened, "null");
+ var undefinedType = createIntrinsicType(TypeFlags.Undefined | TypeFlags.ContainsUndefinedOrNull, "undefined");
+ var nullType = createIntrinsicType(TypeFlags.Null | TypeFlags.ContainsUndefinedOrNull, "null");
var unknownType = createIntrinsicType(TypeFlags.Any, "unknown");
var resolvingType = createIntrinsicType(TypeFlags.Any, "__resolving__");
@@ -107,6 +107,21 @@ module ts {
var diagnostics: Diagnostic[] = [];
var diagnosticsModified: boolean = false;
+ var primitiveTypeInfo: Map<{ type: Type; flags: TypeFlags }> = {
+ "string": {
+ type: stringType,
+ flags: TypeFlags.StringLike
+ },
+ "number": {
+ type: numberType,
+ flags: TypeFlags.NumberLike
+ },
+ "boolean": {
+ type: booleanType,
+ flags: TypeFlags.Boolean
+ }
+ };
+
function addDiagnostic(diagnostic: Diagnostic) {
diagnostics.push(diagnostic);
diagnosticsModified = true;
@@ -337,6 +352,25 @@ module ts {
break loop;
}
break;
+
+ // It is not legal to reference a class's own type parameters from a computed property name that
+ // belongs to the class. For example:
+ //
+ // function foo() { return '' }
+ // class C { // <-- Class's own type parameter T
+ // [foo()]() { } // <-- Reference to T from class's own computed property
+ // }
+ //
+ case SyntaxKind.ComputedPropertyName:
+ var grandparent = location.parent.parent;
+ if (grandparent.kind === SyntaxKind.ClassDeclaration || grandparent.kind === SyntaxKind.InterfaceDeclaration) {
+ // A reference to this grandparent's type parameters would be an error
+ if (result = getSymbol(getSymbolOfNode(grandparent).members, name, meaning & SymbolFlags.Type)) {
+ error(errorLocation, Diagnostics.A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type);
+ return undefined;
+ }
+ }
+ break;
case SyntaxKind.MethodDeclaration:
case SyntaxKind.MethodSignature:
case SyntaxKind.Constructor:
@@ -1660,7 +1694,7 @@ module ts {
// Use type of the specified property, or otherwise, for a numeric name, the type of the numeric index signature,
// or otherwise the type of the string index signature.
var type = getTypeOfPropertyOfType(parentType, name.text) ||
- isNumericName(name.text) && getIndexTypeOfType(parentType, IndexKind.Number) ||
+ isNumericLiteralName(name.text) && getIndexTypeOfType(parentType, IndexKind.Number) ||
getIndexTypeOfType(parentType, IndexKind.String);
if (!type) {
error(name, Diagnostics.Type_0_has_no_property_1_and_no_string_index_signature, typeToString(parentType), declarationNameToString(name));
@@ -1706,7 +1740,7 @@ module ts {
if (declaration.kind === SyntaxKind.Parameter) {
var func = declaration.parent;
// For a parameter of a set accessor, use the type of the get accessor if one is present
- if (func.kind === SyntaxKind.SetAccessor && !hasComputedNameButNotSymbol(func)) {
+ if (func.kind === SyntaxKind.SetAccessor && !hasDynamicName(func)) {
var getter = getDeclarationOfKind(declaration.parent.symbol, SyntaxKind.GetAccessor);
if (getter) {
return getReturnTypeOfSignature(getSignatureFromDeclaration(getter));
@@ -2622,7 +2656,7 @@ module ts {
else {
// TypeScript 1.0 spec (April 2014):
// If only one accessor includes a type annotation, the other behaves as if it had the same type annotation.
- if (declaration.kind === SyntaxKind.GetAccessor && !hasComputedNameButNotSymbol(declaration)) {
+ if (declaration.kind === SyntaxKind.GetAccessor && !hasDynamicName(declaration)) {
var setter = getDeclarationOfKind(declaration.symbol, SyntaxKind.SetAccessor);
returnType = getAnnotatedAccessorType(setter);
}
@@ -2807,15 +2841,22 @@ module ts {
}
}
- function getUnwidenedFlagOfTypes(types: Type[]): TypeFlags {
- return forEach(types, t => t.flags & TypeFlags.Unwidened) || 0;
+ // This function is used to propagate widening flags when creating new object types references and union types.
+ // It is only necessary to do so if a constituent type might be the undefined type, the null type, or the type
+ // of an object literal (since those types have widening related information we need to track).
+ function getWideningFlagsOfTypes(types: Type[]): TypeFlags {
+ var result: TypeFlags = 0;
+ for (var i = 0; i < types.length; i++) {
+ result |= types[i].flags;
+ }
+ return result & TypeFlags.RequiresWidening;
}
function createTypeReference(target: GenericType, typeArguments: Type[]): TypeReference {
var id = getTypeListId(typeArguments);
var type = target.instantiations[id];
if (!type) {
- var flags = TypeFlags.Reference | getUnwidenedFlagOfTypes(typeArguments);
+ var flags = TypeFlags.Reference | getWideningFlagsOfTypes(typeArguments);
type = target.instantiations[id] = createObjectType(flags, target.symbol);
type.target = target;
type.typeArguments = typeArguments;
@@ -3076,7 +3117,7 @@ module ts {
var id = getTypeListId(sortedTypes);
var type = unionTypes[id];
if (!type) {
- type = unionTypes[id] = createObjectType(TypeFlags.Union | getUnwidenedFlagOfTypes(sortedTypes));
+ type = unionTypes[id] = createObjectType(TypeFlags.Union | getWideningFlagsOfTypes(sortedTypes));
type.types = sortedTypes;
}
return type;
@@ -3367,9 +3408,9 @@ module ts {
// TYPE CHECKING
- var subtypeRelation: Map = {};
- var assignableRelation: Map = {};
- var identityRelation: Map = {};
+ var subtypeRelation: Map = {};
+ var assignableRelation: Map = {};
+ var identityRelation: Map = {};
function isTypeIdenticalTo(source: Type, target: Type): boolean {
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined);
@@ -3404,7 +3445,7 @@ module ts {
function checkTypeRelatedTo(
source: Type,
target: Type,
- relation: Map,
+ relation: Map,
errorNode: Node,
headMessage?: DiagnosticMessage,
containingMessageChain?: DiagnosticMessageChain): boolean {
@@ -3412,7 +3453,7 @@ module ts {
var errorInfo: DiagnosticMessageChain;
var sourceStack: ObjectType[];
var targetStack: ObjectType[];
- var maybeStack: Map[];
+ var maybeStack: Map[];
var expandingFlags: number;
var depth = 0;
var overflow = false;
@@ -3424,6 +3465,14 @@ module ts {
error(errorNode, Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, typeToString(source), typeToString(target));
}
else if (errorInfo) {
+ // If we already computed this relation, but in a context where we didn't want to report errors (e.g. overload resolution),
+ // then we'll only have a top-level error (e.g. 'Class X does not implement interface Y') without any details. If this happened,
+ // request a recompuation to get a complete error message. This will be skipped if we've already done this computation in a context
+ // where errors were being reported.
+ if (errorInfo.next === undefined) {
+ errorInfo = undefined;
+ isRelatedTo(source, target, errorNode !== undefined, headMessage, /* elaborateErrors */ true);
+ }
if (containingMessageChain) {
errorInfo = concatenateDiagnosticMessageChains(containingMessageChain, errorInfo);
}
@@ -3439,7 +3488,7 @@ module ts {
// Ternary.True if they are related with no assumptions,
// Ternary.Maybe if they are related with assumptions of other relationships, or
// Ternary.False if they are not related.
- function isRelatedTo(source: Type, target: Type, reportErrors?: boolean, headMessage?: DiagnosticMessage): Ternary {
+ function isRelatedTo(source: Type, target: Type, reportErrors?: boolean, headMessage?: DiagnosticMessage, elaborateErrors = false): Ternary {
var result: Ternary;
// both types are the same - covers 'they are the same primitive type or both are Any' or the same type parameter cases
if (source === target) return Ternary.True;
@@ -3506,7 +3555,7 @@ module ts {
// identity relation does not use apparent type
var sourceOrApparentType = relation === identityRelation ? source : getApparentType(source);
if (sourceOrApparentType.flags & TypeFlags.ObjectType && target.flags & TypeFlags.ObjectType &&
- (result = objectTypeRelatedTo(sourceOrApparentType, target, reportStructuralErrors))) {
+ (result = objectTypeRelatedTo(sourceOrApparentType, target, reportStructuralErrors, elaborateErrors))) {
errorInfo = saveErrorInfo;
return result;
}
@@ -3597,14 +3646,19 @@ module ts {
// Third, check if both types are part of deeply nested chains of generic type instantiations and if so assume the types are
// equal and infinitely expanding. Fourth, if we have reached a depth of 100 nested comparisons, assume we have runaway recursion
// and issue an error. Otherwise, actually compare the structure of the two types.
- function objectTypeRelatedTo(source: ObjectType, target: ObjectType, reportErrors: boolean): Ternary {
+ function objectTypeRelatedTo(source: ObjectType, target: ObjectType, reportErrors: boolean, elaborateErrors = false): Ternary {
if (overflow) {
return Ternary.False;
}
var id = relation !== identityRelation || source.id < target.id ? source.id + "," + target.id : target.id + "," + source.id;
var related = relation[id];
+ //var related: RelationComparisonResult = undefined; // relation[id];
if (related !== undefined) {
- return related ? Ternary.True : Ternary.False;
+ // If we computed this relation already and it was failed and reported, or if we're not being asked to elaborate
+ // errors, we can use the cached value. Otherwise, recompute the relation
+ if (!elaborateErrors || (related === RelationComparisonResult.FailedAndReported)) {
+ return related === RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False;
+ }
}
if (depth > 0) {
for (var i = 0; i < depth; i++) {
@@ -3627,7 +3681,7 @@ module ts {
sourceStack[depth] = source;
targetStack[depth] = target;
maybeStack[depth] = {};
- maybeStack[depth][id] = true;
+ maybeStack[depth][id] = RelationComparisonResult.Succeeded;
depth++;
var saveExpandingFlags = expandingFlags;
if (!(expandingFlags & 1) && isDeeplyNestedGeneric(source, sourceStack)) expandingFlags |= 1;
@@ -3655,13 +3709,13 @@ module ts {
if (result) {
var maybeCache = maybeStack[depth];
// If result is definitely true, copy assumptions to global cache, else copy to next level up
- var destinationCache = result === Ternary.True || depth === 0 ? relation : maybeStack[depth - 1];
- copyMap(/*source*/maybeCache, /*target*/destinationCache);
+ var destinationCache = (result === Ternary.True || depth === 0) ? relation : maybeStack[depth - 1];
+ copyMap(maybeCache, destinationCache);
}
else {
// A false result goes straight into global cache (when something is false under assumptions it
// will also be false without assumptions)
- relation[id] = false;
+ relation[id] = reportErrors ? RelationComparisonResult.FailedAndReported : RelationComparisonResult.Failed;
}
return result;
}
@@ -3692,12 +3746,13 @@ module ts {
}
var result = Ternary.True;
var properties = getPropertiesOfObjectType(target);
+ var requireOptionalProperties = relation === subtypeRelation && !(source.flags & TypeFlags.ObjectLiteral);
for (var i = 0; i < properties.length; i++) {
var targetProp = properties[i];
var sourceProp = getPropertyOfType(source, targetProp.name);
if (sourceProp !== targetProp) {
if (!sourceProp) {
- if (relation === subtypeRelation || !(targetProp.flags & SymbolFlags.Optional)) {
+ if (!(targetProp.flags & SymbolFlags.Optional) || requireOptionalProperties) {
if (reportErrors) {
reportError(Diagnostics.Property_0_is_missing_in_type_1, symbolToString(targetProp), typeToString(source));
}
@@ -4088,10 +4143,6 @@ module ts {
errorMessageChainHead);
}
- function isTypeOfObjectLiteral(type: Type): boolean {
- return (type.flags & TypeFlags.Anonymous) && type.symbol && (type.symbol.flags & SymbolFlags.ObjectLiteral) ? true : false;
- }
-
function isArrayType(type: Type): boolean {
return type.flags & TypeFlags.Reference && (type).target === globalArrayType;
}
@@ -4104,13 +4155,18 @@ module ts {
var properties = getPropertiesOfObjectType(type);
var members: SymbolTable = {};
forEach(properties, p => {
- var symbol = createSymbol(p.flags | SymbolFlags.Transient, p.name);
- symbol.declarations = p.declarations;
- symbol.parent = p.parent;
- symbol.type = getWidenedType(getTypeOfSymbol(p));
- symbol.target = p;
- if (p.valueDeclaration) symbol.valueDeclaration = p.valueDeclaration;
- members[symbol.name] = symbol;
+ var propType = getTypeOfSymbol(p);
+ var widenedType = getWidenedType(propType);
+ if (propType !== widenedType) {
+ var symbol = createSymbol(p.flags | SymbolFlags.Transient, p.name);
+ symbol.declarations = p.declarations;
+ symbol.parent = p.parent;
+ symbol.type = widenedType;
+ symbol.target = p;
+ if (p.valueDeclaration) symbol.valueDeclaration = p.valueDeclaration;
+ p = symbol;
+ }
+ members[p.name] = p;
});
var stringIndexType = getIndexTypeOfType(type, IndexKind.String);
var numberIndexType = getIndexTypeOfType(type, IndexKind.Number);
@@ -4120,16 +4176,16 @@ module ts {
}
function getWidenedType(type: Type): Type {
- if (type.flags & TypeFlags.Unwidened) {
+ if (type.flags & TypeFlags.RequiresWidening) {
if (type.flags & (TypeFlags.Undefined | TypeFlags.Null)) {
return anyType;
}
+ if (type.flags & TypeFlags.ObjectLiteral) {
+ return getWidenedTypeOfObjectLiteral(type);
+ }
if (type.flags & TypeFlags.Union) {
return getUnionType(map((type).types, getWidenedType));
}
- if (isTypeOfObjectLiteral(type)) {
- return getWidenedTypeOfObjectLiteral(type);
- }
if (isArrayType(type)) {
return createArrayType(getWidenedType((type).typeArguments[0]));
}
@@ -4150,11 +4206,11 @@ module ts {
if (isArrayType(type)) {
return reportWideningErrorsInType((type).typeArguments[0]);
}
- if (isTypeOfObjectLiteral(type)) {
+ if (type.flags & TypeFlags.ObjectLiteral) {
var errorReported = false;
forEach(getPropertiesOfObjectType(type), p => {
var t = getTypeOfSymbol(p);
- if (t.flags & TypeFlags.Unwidened) {
+ if (t.flags & TypeFlags.ContainsUndefinedOrNull) {
if (!reportWideningErrorsInType(t)) {
error(p.valueDeclaration, Diagnostics.Object_literal_s_property_0_implicitly_has_an_1_type, p.name, typeToString(getWidenedType(t)));
}
@@ -4198,7 +4254,7 @@ module ts {
}
function reportErrorsFromWidening(declaration: Declaration, type: Type) {
- if (produceDiagnostics && compilerOptions.noImplicitAny && type.flags & TypeFlags.Unwidened) {
+ if (produceDiagnostics && compilerOptions.noImplicitAny && type.flags & TypeFlags.ContainsUndefinedOrNull) {
// Report implicit any error within type if possible, otherwise report error on declaration
if (!reportWideningErrorsInType(type)) {
reportImplicitAnyError(declaration, type);
@@ -4454,12 +4510,17 @@ module ts {
Debug.fail("should not get here");
}
- // Remove one or more primitive types from a union type
- function subtractPrimitiveTypes(type: Type, subtractMask: TypeFlags): Type {
+ // For a union type, remove all constituent types that are of the given type kind (when isOfTypeKind is true)
+ // or not of the given type kind (when isOfTypeKind is false)
+ function removeTypesFromUnionType(type: Type, typeKind: TypeFlags, isOfTypeKind: boolean): Type {
if (type.flags & TypeFlags.Union) {
var types = (type).types;
- if (forEach(types, t => t.flags & subtractMask)) {
- return getUnionType(filter(types, t => !(t.flags & subtractMask)));
+ if (forEach(types, t => !!(t.flags & typeKind) === isOfTypeKind)) {
+ // Above we checked if we have anything to remove, now use the opposite test to do the removal
+ var narrowedType = getUnionType(filter(types, t => !(t.flags & typeKind) === isOfTypeKind));
+ if (narrowedType !== emptyObjectType) {
+ return narrowedType;
+ }
}
}
return type;
@@ -4635,8 +4696,8 @@ module ts {
// Stop at the first containing function or module declaration
break loop;
}
- // Use narrowed type if it is a subtype and construct contains no assignments to variable
- if (narrowedType !== type && isTypeSubtypeOf(narrowedType, type)) {
+ // Use narrowed type if construct contains no assignments to variable
+ if (narrowedType !== type) {
if (isVariableAssignedWithin(symbol, node)) {
break;
}
@@ -4656,20 +4717,30 @@ module ts {
if (left.expression.kind !== SyntaxKind.Identifier || getResolvedSymbol(left.expression) !== symbol) {
return type;
}
- var t = right.text;
- var checkType: Type = t === "string" ? stringType : t === "number" ? numberType : t === "boolean" ? booleanType : emptyObjectType;
+ var typeInfo = primitiveTypeInfo[right.text];
if (expr.operator === SyntaxKind.ExclamationEqualsEqualsToken) {
assumeTrue = !assumeTrue;
}
if (assumeTrue) {
- // The assumed result is true. If check was for a primitive type, that type is the narrowed type. Otherwise we can
- // remove the primitive types from the narrowed type.
- return checkType === emptyObjectType ? subtractPrimitiveTypes(type, TypeFlags.String | TypeFlags.Number | TypeFlags.Boolean) : checkType;
+ // Assumed result is true. If check was not for a primitive type, remove all primitive types
+ if (!typeInfo) {
+ return removeTypesFromUnionType(type, /*typeKind*/ TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.Boolean, /*isOfTypeKind*/ true);
+ }
+ // Check was for a primitive type, return that primitive type if it is a subtype
+ if (isTypeSubtypeOf(typeInfo.type, type)) {
+ return typeInfo.type;
+ }
+ // Otherwise, remove all types that aren't of the primitive type kind. This can happen when the type is
+ // union of enum types and other types.
+ return removeTypesFromUnionType(type, /*typeKind*/ typeInfo.flags, /*isOfTypeKind*/ false);
}
else {
- // The assumed result is false. If check was for a primitive type we can remove that type from the narrowed type.
+ // Assumed result is false. If check was for a primitive type, remove that primitive type
+ if (typeInfo) {
+ return removeTypesFromUnionType(type, /*typeKind*/ typeInfo.flags, /*isOfTypeKind*/ true);
+ }
// Otherwise we don't have enough information to do anything.
- return checkType === emptyObjectType ? type : subtractPrimitiveTypes(type, checkType.flags);
+ return type;
}
}
@@ -4730,7 +4801,8 @@ module ts {
return type;
}
- // Narrow the given type based on the given expression having the assumed boolean value
+ // Narrow the given type based on the given expression having the assumed boolean value. The returned type
+ // will be a subtype or the same type as the argument.
function narrowType(type: Type, expr: Expression, assumeTrue: boolean): Type {
switch (expr.kind) {
case SyntaxKind.ParenthesizedExpression:
@@ -4759,6 +4831,7 @@ module ts {
return type;
}
}
+
/*Transitively mark all linked imports as referenced*/
function markLinkedImportsAsReferenced(node: ImportDeclaration): void {
var nodeLinks = getNodeLinks(node);
@@ -4855,6 +4928,9 @@ module ts {
// do not return here so in case if lexical this is captured - it will be reflected in flags on NodeLinks
}
break;
+ case SyntaxKind.ComputedPropertyName:
+ error(node, Diagnostics.this_cannot_be_referenced_in_a_computed_property_name);
+ break;
}
if (needToCaptureLexicalThis) {
@@ -4869,26 +4945,6 @@ module ts {
return anyType;
}
- function getSuperContainer(node: Node): Node {
- while (true) {
- node = node.parent;
- if (!node) return node;
- switch (node.kind) {
- case SyntaxKind.FunctionDeclaration:
- case SyntaxKind.FunctionExpression:
- case SyntaxKind.ArrowFunction:
- case SyntaxKind.PropertyDeclaration:
- case SyntaxKind.PropertySignature:
- case SyntaxKind.MethodDeclaration:
- case SyntaxKind.MethodSignature:
- case SyntaxKind.Constructor:
- case SyntaxKind.GetAccessor:
- case SyntaxKind.SetAccessor:
- return node;
- }
- }
- }
-
function isInConstructorArgumentInitializer(node: Node, constructorDecl: Node): boolean {
for (var n = node; n && n !== constructorDecl; n = n.parent) {
if (n.kind === SyntaxKind.Parameter) {
@@ -4912,7 +4968,7 @@ module ts {
return unknownType;
}
- var container = getSuperContainer(node);
+ var container = getSuperContainer(node, /*includeFunctions*/ true);
if (container) {
var canUseSuperExpression = false;
@@ -4930,7 +4986,7 @@ module ts {
// super property access might appear in arrow functions with arbitrary deep nesting
var needToCaptureLexicalThis = false;
while (container && container.kind === SyntaxKind.ArrowFunction) {
- container = getSuperContainer(container);
+ container = getSuperContainer(container, /*includeFunctions*/ true);
needToCaptureLexicalThis = true;
}
@@ -4985,7 +5041,10 @@ module ts {
}
}
- if (isCallExpression) {
+ if (container.kind === SyntaxKind.ComputedPropertyName) {
+ error(node, Diagnostics.super_cannot_be_referenced_in_a_computed_property_name);
+ }
+ else if (isCallExpression) {
error(node, Diagnostics.Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors);
}
else {
@@ -5167,13 +5226,22 @@ module ts {
function getContextualTypeForObjectLiteralElement(element: ObjectLiteralElement) {
var objectLiteral = element.parent;
var type = getContextualType(objectLiteral);
- // TODO(jfreeman): Handle this case for computed names and symbols
- var name = (element.name).text;
- if (type && name) {
- return getTypeOfPropertyOfContextualType(type, name) ||
- isNumericName(name) && getIndexTypeOfContextualType(type, IndexKind.Number) ||
+ if (type) {
+ if (!hasDynamicName(element)) {
+ // For a (non-symbol) computed property, there is no reason to look up the name
+ // in the type. It will just be "__computed", which does not appear in any
+ // SymbolTable.
+ var symbolName = getSymbolOfNode(element).name;
+ var propertyType = getTypeOfPropertyOfContextualType(type, symbolName);
+ if (propertyType) {
+ return propertyType;
+ }
+ }
+
+ return isNumericName(element.name) && getIndexTypeOfContextualType(type, IndexKind.Number) ||
getIndexTypeOfContextualType(type, IndexKind.String);
}
+
return undefined;
}
@@ -5372,7 +5440,17 @@ module ts {
return createArrayType(getUnionType(elementTypes));
}
- function isNumericName(name: string) {
+ function isNumericName(name: DeclarationName): boolean {
+ return name.kind === SyntaxKind.ComputedPropertyName ? isNumericComputedName(name) : isNumericLiteralName((name).text);
+ }
+
+ function isNumericComputedName(name: ComputedPropertyName): boolean {
+ // It seems odd to consider an expression of type Any to result in a numeric name,
+ // but this behavior is consistent with checkIndexedAccess
+ return isTypeOfKind(checkComputedPropertyName(name), TypeFlags.Any | TypeFlags.NumberLike);
+ }
+
+ function isNumericLiteralName(name: string) {
// The intent of numeric names is that
// - they are names with text in a numeric form, and that
// - setting properties/indexing with them is always equivalent to doing so with the numeric literal 'numLit',
@@ -5397,84 +5475,101 @@ module ts {
return (+name).toString() === name;
}
+ function checkComputedPropertyName(node: ComputedPropertyName): Type {
+ var links = getNodeLinks(node.expression);
+ if (!links.resolvedType) {
+ links.resolvedType = checkExpression(node.expression);
+
+ // This will allow types number, string, or any. It will also allow enums, the unknown
+ // type, and any union of these types (like string | number).
+ if (!isTypeOfKind(links.resolvedType, TypeFlags.Any | TypeFlags.NumberLike | TypeFlags.StringLike)) {
+ error(node, Diagnostics.A_computed_property_name_must_be_of_type_string_number_or_any);
+ }
+ }
+
+ return links.resolvedType;
+ }
+
function checkObjectLiteral(node: ObjectLiteralExpression, contextualMapper?: TypeMapper): Type {
// Grammar checking
checkGrammarObjectLiteralExpression(node);
- var members = node.symbol.members;
- var properties: SymbolTable = {};
+ var propertiesTable: SymbolTable = {};
+ var propertiesArray: Symbol[] = [];
var contextualType = getContextualType(node);
var typeFlags: TypeFlags;
- for (var id in members) {
- if (hasProperty(members, id)) {
- var member = members[id];
- if (member.flags & SymbolFlags.Property || isObjectLiteralMethod(member.declarations[0])) {
- var memberDecl = member.declarations[0];
- if (memberDecl.kind === SyntaxKind.PropertyAssignment) {
- var type = checkExpression((memberDecl).initializer, contextualMapper);
- }
- else if (memberDecl.kind === SyntaxKind.MethodDeclaration) {
- var type = checkObjectLiteralMethod(memberDecl, contextualMapper);
- }
- else {
- Debug.assert(memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment);
- var type = memberDecl.name.kind === SyntaxKind.ComputedPropertyName
- ? unknownType
- : checkExpression(memberDecl.name, contextualMapper);
- }
- typeFlags |= type.flags;
- var prop = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | member.flags, member.name);
- prop.declarations = member.declarations;
- prop.parent = member.parent;
- if (member.valueDeclaration) {
- prop.valueDeclaration = member.valueDeclaration;
- }
-
- prop.type = type;
- prop.target = member;
- member = prop;
+ for (var i = 0; i < node.properties.length; i++) {
+ var memberDecl = node.properties[i];
+ var member = memberDecl.symbol;
+ if (memberDecl.kind === SyntaxKind.PropertyAssignment ||
+ memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment ||
+ isObjectLiteralMethod(memberDecl)) {
+ if (memberDecl.kind === SyntaxKind.PropertyAssignment) {
+ var type = checkPropertyAssignment(memberDecl, contextualMapper);
+ }
+ else if (memberDecl.kind === SyntaxKind.MethodDeclaration) {
+ var type = checkObjectLiteralMethod(memberDecl, contextualMapper);
}
else {
- // TypeScript 1.0 spec (April 2014)
- // A get accessor declaration is processed in the same manner as
- // an ordinary function declaration(section 6.1) with no parameters.
- // A set accessor declaration is processed in the same manner
- // as an ordinary function declaration with a single parameter and a Void return type.
- var getAccessor = getDeclarationOfKind(member, SyntaxKind.GetAccessor);
- if (getAccessor) {
- checkAccessorDeclaration(getAccessor);
- }
-
- var setAccessor = getDeclarationOfKind(member, SyntaxKind.SetAccessor);
- if (setAccessor) {
- checkAccessorDeclaration(setAccessor);
- }
+ Debug.assert(memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment);
+ var type = memberDecl.name.kind === SyntaxKind.ComputedPropertyName
+ ? unknownType
+ : checkExpression(memberDecl.name, contextualMapper);
}
- properties[member.name] = member;
+ typeFlags |= type.flags;
+ var prop = createSymbol(SymbolFlags.Property | SymbolFlags.Transient | member.flags, member.name);
+ prop.declarations = member.declarations;
+ prop.parent = member.parent;
+ if (member.valueDeclaration) {
+ prop.valueDeclaration = member.valueDeclaration;
+ }
+
+ prop.type = type;
+ prop.target = member;
+ member = prop;
}
+ else {
+ // TypeScript 1.0 spec (April 2014)
+ // A get accessor declaration is processed in the same manner as
+ // an ordinary function declaration(section 6.1) with no parameters.
+ // A set accessor declaration is processed in the same manner
+ // as an ordinary function declaration with a single parameter and a Void return type.
+ Debug.assert(memberDecl.kind === SyntaxKind.GetAccessor || memberDecl.kind === SyntaxKind.SetAccessor);
+ checkAccessorDeclaration(memberDecl);
+ }
+
+ if (!hasDynamicName(memberDecl)) {
+ propertiesTable[member.name] = member;
+ }
+ propertiesArray.push(member);
}
var stringIndexType = getIndexType(IndexKind.String);
var numberIndexType = getIndexType(IndexKind.Number);
- var result = createAnonymousType(node.symbol, properties, emptyArray, emptyArray, stringIndexType, numberIndexType);
- result.flags |= (typeFlags & TypeFlags.Unwidened);
+ var result = createAnonymousType(node.symbol, propertiesTable, emptyArray, emptyArray, stringIndexType, numberIndexType);
+ result.flags |= TypeFlags.ObjectLiteral | TypeFlags.ContainsObjectLiteral | (typeFlags & TypeFlags.ContainsUndefinedOrNull);
return result;
function getIndexType(kind: IndexKind) {
if (contextualType && contextualTypeHasIndexSignature(contextualType, kind)) {
var propTypes: Type[] = [];
- for (var id in properties) {
- if (hasProperty(properties, id)) {
- if (kind === IndexKind.String || isNumericName(id)) {
- var type = getTypeOfSymbol(properties[id]);
- if (!contains(propTypes, type)) {
- propTypes.push(type);
- }
+ for (var i = 0; i < propertiesArray.length; i++) {
+ var propertyDecl = node.properties[i];
+ if (kind === IndexKind.String || isNumericName(propertyDecl.name)) {
+ // Do not call getSymbolOfNode(propertyDecl), as that will get the
+ // original symbol for the node. We actually want to get the symbol
+ // created by checkObjectLiteral, since that will be appropriately
+ // contextually typed and resolved.
+ var type = getTypeOfSymbol(propertiesArray[i]);
+ if (!contains(propTypes, type)) {
+ propTypes.push(type);
}
}
}
- return propTypes.length ? getUnionType(propTypes) : undefinedType;
+ var result = propTypes.length ? getUnionType(propTypes) : undefinedType;
+ typeFlags |= result.flags;
+ return result;
}
return undefined;
}
@@ -5867,7 +5962,7 @@ module ts {
return typeArgumentsAreAssignable;
}
- function checkApplicableSignature(node: CallLikeExpression, args: Node[], signature: Signature, relation: Map, excludeArgument: boolean[], reportErrors: boolean) {
+ function checkApplicableSignature(node: CallLikeExpression, args: Node[], signature: Signature, relation: Map, excludeArgument: boolean[], reportErrors: boolean) {
for (var i = 0; i < args.length; i++) {
var arg = args[i];
var argType: Type;
@@ -5927,11 +6022,41 @@ module ts {
return args;
}
+ /**
+ * In a 'super' call, type arguments are not provided within the CallExpression node itself.
+ * Instead, they must be fetched from the class declaration's base type node.
+ *
+ * If 'node' is a 'super' call (e.g. super(...), new super(...)), then we attempt to fetch
+ * the type arguments off the containing class's first heritage clause (if one exists). Note that if
+ * type arguments are supplied on the 'super' call, they are ignored (though this is syntactically incorrect).
+ *
+ * In all other cases, the call's explicit type arguments are returned.
+ */
+ function getEffectiveTypeArguments(callExpression: CallExpression): TypeNode[] {
+ if (callExpression.expression.kind === SyntaxKind.SuperKeyword) {
+ var containingClass = getAncestor(callExpression, SyntaxKind.ClassDeclaration);
+ var baseClassTypeNode = containingClass && getClassBaseTypeNode(containingClass);
+ return baseClassTypeNode && baseClassTypeNode.typeArguments;
+ }
+ else {
+ // Ordinary case - simple function invocation.
+ return callExpression.typeArguments;
+ }
+ }
+
function resolveCall(node: CallLikeExpression, signatures: Signature[], candidatesOutArray: Signature[]): Signature {
var isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression;
- var typeArguments = isTaggedTemplate ? undefined : (node).typeArguments;
- forEach(typeArguments, checkSourceElement);
+ var typeArguments: TypeNode[];
+
+ if (!isTaggedTemplate) {
+ typeArguments = getEffectiveTypeArguments(node);
+
+ // We already perform checking on the type arguments on the class declaration itself.
+ if ((node).expression.kind !== SyntaxKind.SuperKeyword) {
+ forEach(typeArguments, checkSourceElement);
+ }
+ }
var candidates = candidatesOutArray || [];
// collectCandidates fills up the candidates array directly
@@ -6061,7 +6186,7 @@ module ts {
return resolveErrorCall(node);
- function chooseOverload(candidates: Signature[], relation: Map) {
+ function chooseOverload(candidates: Signature[], relation: Map) {
for (var i = 0; i < candidates.length; i++) {
if (!hasCorrectArity(node, args, candidates[i])) {
continue;
@@ -6197,7 +6322,7 @@ module ts {
// Another error has already been reported
return resolveErrorCall(node);
}
-
+
// Technically, this signatures list may be incomplete. We are taking the apparent type,
// but we are not including call signatures that may have been added to the Object or
// Function interface, since they have none by default. This is a bit of a leap of faith
@@ -6738,7 +6863,7 @@ module ts {
// and the right operand to be of type Any or a subtype of the 'Function' interface type.
// The result is always of the Boolean primitive type.
// NOTE: do not raise error if leftType is unknown as related error was already reported
- if (!isTypeOfKind(leftType, TypeFlags.Any | TypeFlags.ObjectType | TypeFlags.TypeParameter)) {
+ if (isTypeOfKind(leftType, TypeFlags.Primitive)) {
error(node.left, Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter);
}
// NOTE: do not raise error if right is unknown as related error was already reported
@@ -6771,7 +6896,7 @@ module ts {
var name = (p).name;
var type = sourceType.flags & TypeFlags.Any ? sourceType :
getTypeOfPropertyOfType(sourceType, name.text) ||
- isNumericName(name.text) && getIndexTypeOfType(sourceType, IndexKind.Number) ||
+ isNumericLiteralName(name.text) && getIndexTypeOfType(sourceType, IndexKind.Number) ||
getIndexTypeOfType(sourceType, IndexKind.String);
if (type) {
checkDestructuringAssignment((p).initializer || name, type);
@@ -7052,10 +7177,22 @@ module ts {
return links.resolvedType;
}
+ function checkPropertyAssignment(node: PropertyAssignment, contextualMapper?: TypeMapper): Type {
+ if (hasDynamicName(node)) {
+ checkComputedPropertyName(node.name);
+ }
+
+ return checkExpression((node).initializer, contextualMapper);
+ }
+
function checkObjectLiteralMethod(node: MethodDeclaration, contextualMapper?: TypeMapper): Type {
// Grammar checking
checkGrammarMethod(node);
+ if (hasDynamicName(node)) {
+ checkComputedPropertyName(node.name);
+ }
+
var uninstantiatedType = checkFunctionExpressionOrObjectLiteralMethod(node, contextualMapper);
return instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, contextualMapper);
}
@@ -7426,7 +7563,7 @@ module ts {
}
}
- if (!hasComputedNameButNotSymbol(node)) {
+ if (!hasDynamicName(node)) {
// TypeScript 1.0 spec (April 2014): 8.4.3
// Accessors for the same member name must specify the same accessibility.
var otherKind = node.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor;
@@ -7446,9 +7583,9 @@ module ts {
}
}
}
-
- checkAndStoreTypeOfAccessors(getSymbolOfNode(node));
}
+
+ checkAndStoreTypeOfAccessors(getSymbolOfNode(node));
}
checkFunctionLikeDeclaration(node);
@@ -7864,7 +8001,12 @@ module ts {
function checkFunctionLikeDeclaration(node: FunctionLikeDeclaration): void {
checkSignatureDeclaration(node);
- if (!hasComputedNameButNotSymbol(node)) {
+ if (hasDynamicName(node)) {
+ // This check will account for methods in class/interface declarations,
+ // as well as accessors in classes/object literals
+ checkComputedPropertyName(node.name);
+ }
+ else {
// first we want to check the local symbol that contain this declaration
// - if node.localSymbol !== undefined - this is current declaration is exported and localSymbol points to the local symbol
// - if node.localSymbol === undefined - this node is non-exported so we can just pick the result of getSymbolOfNode
@@ -8093,7 +8235,8 @@ module ts {
function checkVariableLikeDeclaration(node: VariableLikeDeclaration) {
checkSourceElement(node.type);
// For a computed property, just check the initializer and exit
- if (hasComputedNameButNotSymbol(node)) {
+ if (hasDynamicName(node)) {
+ checkComputedPropertyName(node.name);
if (node.initializer) {
checkExpressionCached(node.initializer);
}
@@ -8436,45 +8579,7 @@ module ts {
if (node.finallyBlock) checkBlock(node.finallyBlock);
}
- function checkIndexConstraints(type: Type) {
-
- function checkIndexConstraintForProperty(prop: Symbol, propertyType: Type, indexDeclaration: Declaration, indexType: Type, indexKind: IndexKind): void {
- if (!indexType) {
- return;
- }
-
- // index is numeric and property name is not valid numeric literal
- if (indexKind === IndexKind.Number && !isNumericName(prop.name)) {
- return;
- }
-
- // perform property check if property or indexer is declared in 'type'
- // this allows to rule out cases when both property and indexer are inherited from the base class
- var errorNode: Node;
- if (prop.parent === type.symbol) {
- errorNode = prop.valueDeclaration;
- }
- else if (indexDeclaration) {
- errorNode = indexDeclaration;
- }
-
- else if (type.flags & TypeFlags.Interface) {
- // for interfaces property and indexer might be inherited from different bases
- // check if any base class already has both property and indexer.
- // check should be performed only if 'type' is the first type that brings property\indexer together
- var someBaseClassHasBothPropertyAndIndexer = forEach((type).baseTypes, base => getPropertyOfObjectType(base, prop.name) && getIndexTypeOfType(base, indexKind));
- errorNode = someBaseClassHasBothPropertyAndIndexer ? undefined : type.symbol.declarations[0];
- }
-
- if (errorNode && !isTypeAssignableTo(propertyType, indexType)) {
- var errorMessage =
- indexKind === IndexKind.String
- ? Diagnostics.Property_0_of_type_1_is_not_assignable_to_string_index_type_2
- : Diagnostics.Property_0_of_type_1_is_not_assignable_to_numeric_index_type_2;
- error(errorNode, errorMessage, symbolToString(prop), typeToString(propertyType), typeToString(indexType));
- }
- }
-
+ function checkIndexConstraints(type: Type) {
var declaredNumberIndexer = getIndexDeclarationOfSymbol(type.symbol, IndexKind.Number);
var declaredStringIndexer = getIndexDeclarationOfSymbol(type.symbol, IndexKind.String);
@@ -8484,9 +8589,24 @@ module ts {
if (stringIndexType || numberIndexType) {
forEach(getPropertiesOfObjectType(type), prop => {
var propType = getTypeOfSymbol(prop);
- checkIndexConstraintForProperty(prop, propType, declaredStringIndexer, stringIndexType, IndexKind.String);
- checkIndexConstraintForProperty(prop, propType, declaredNumberIndexer, numberIndexType, IndexKind.Number);
+ checkIndexConstraintForProperty(prop, propType, type, declaredStringIndexer, stringIndexType, IndexKind.String);
+ checkIndexConstraintForProperty(prop, propType, type, declaredNumberIndexer, numberIndexType, IndexKind.Number);
});
+
+ if (type.flags & TypeFlags.Class && type.symbol.valueDeclaration.kind === SyntaxKind.ClassDeclaration) {
+ var classDeclaration = type.symbol.valueDeclaration;
+ for (var i = 0; i < classDeclaration.members.length; i++) {
+ var member = classDeclaration.members[i];
+ // Only process instance properties with computed names here.
+ // Static properties cannot be in conflict with indexers,
+ // and properties with literal names were already checked.
+ if (!(member.flags & NodeFlags.Static) && hasDynamicName(member)) {
+ var propType = getTypeOfSymbol(member.symbol);
+ checkIndexConstraintForProperty(member.symbol, propType, type, declaredStringIndexer, stringIndexType, IndexKind.String);
+ checkIndexConstraintForProperty(member.symbol, propType, type, declaredNumberIndexer, numberIndexType, IndexKind.Number);
+ }
+ }
+ }
}
var errorNode: Node;
@@ -8503,9 +8623,51 @@ module ts {
error(errorNode, Diagnostics.Numeric_index_type_0_is_not_assignable_to_string_index_type_1,
typeToString(numberIndexType), typeToString(stringIndexType));
}
+
+ function checkIndexConstraintForProperty(
+ prop: Symbol,
+ propertyType: Type,
+ containingType: Type,
+ indexDeclaration: Declaration,
+ indexType: Type,
+ indexKind: IndexKind): void {
+
+ if (!indexType) {
+ return;
+ }
+
+ // index is numeric and property name is not valid numeric literal
+ if (indexKind === IndexKind.Number && !isNumericName(prop.valueDeclaration.name)) {
+ return;
+ }
+
+ // perform property check if property or indexer is declared in 'type'
+ // this allows to rule out cases when both property and indexer are inherited from the base class
+ var errorNode: Node;
+ if (prop.valueDeclaration.name.kind === SyntaxKind.ComputedPropertyName || prop.parent === containingType.symbol) {
+ errorNode = prop.valueDeclaration;
+ }
+ else if (indexDeclaration) {
+ errorNode = indexDeclaration;
+ }
+ else if (containingType.flags & TypeFlags.Interface) {
+ // for interfaces property and indexer might be inherited from different bases
+ // check if any base class already has both property and indexer.
+ // check should be performed only if 'type' is the first type that brings property\indexer together
+ var someBaseClassHasBothPropertyAndIndexer = forEach((containingType).baseTypes, base => getPropertyOfObjectType(base, prop.name) && getIndexTypeOfType(base, indexKind));
+ errorNode = someBaseClassHasBothPropertyAndIndexer ? undefined : containingType.symbol.declarations[0];
+ }
+
+ if (errorNode && !isTypeAssignableTo(propertyType, indexType)) {
+ var errorMessage =
+ indexKind === IndexKind.String
+ ? Diagnostics.Property_0_of_type_1_is_not_assignable_to_string_index_type_2
+ : Diagnostics.Property_0_of_type_1_is_not_assignable_to_numeric_index_type_2;
+ error(errorNode, errorMessage, symbolToString(prop), typeToString(propertyType), typeToString(indexType));
+ }
+ }
}
- // TODO(jfreeman): Decide what to do for computed properties
function checkTypeNameIsReserved(name: DeclarationName, message: DiagnosticMessage): void {
// TS 1.0 spec (April 2014): 3.6.1
// The predefined type keywords are reserved and cannot be used as names of user defined types.
@@ -8799,8 +8961,7 @@ module ts {
var enumIsConst = isConst(node);
forEach(node.members, member => {
- // TODO(jfreeman): Check that it is not a computed name
- if(isNumericName((member.name).text)) {
+ if (member.name.kind !== SyntaxKind.ComputedPropertyName && isNumericLiteralName((member.name).text)) {
error(member.name, Diagnostics.An_enum_member_cannot_have_a_numeric_name);
}
var initializer = member.initializer;
@@ -9990,8 +10151,8 @@ module ts {
if (symbol && (symbol.flags & SymbolFlags.EnumMember)) {
var declaration = symbol.valueDeclaration;
var constantValue: number;
- if (declaration.kind === SyntaxKind.EnumMember && (constantValue = getNodeLinks(declaration).enumMemberValue) !== undefined) {
- return constantValue;
+ if (declaration.kind === SyntaxKind.EnumMember) {
+ return getEnumMemberValue(declaration);
}
}
@@ -10427,22 +10588,18 @@ module ts {
return false;
}
- function checkGrammarComputedPropertyName(node: Node): void {
+ function checkGrammarComputedPropertyName(node: Node): boolean {
// If node is not a computedPropertyName, just skip the grammar checking
if (node.kind !== SyntaxKind.ComputedPropertyName) {
- return;
+ return false;
}
- // Since computed properties are not supported in the type checker, disallow them in TypeScript 1.4
- // Once full support is added, remove this error.
- grammarErrorOnNode(node, Diagnostics.Computed_property_names_are_not_currently_supported);
- return;
var computedPropertyName = node;
if (languageVersion < ScriptTarget.ES6) {
- grammarErrorOnNode(node, Diagnostics.Computed_property_names_are_only_available_when_targeting_ECMAScript_6_and_higher);
+ return grammarErrorOnNode(node, Diagnostics.Computed_property_names_are_only_available_when_targeting_ECMAScript_6_and_higher);
}
else if (computedPropertyName.expression.kind === SyntaxKind.BinaryExpression && (computedPropertyName.expression).operator === SyntaxKind.CommaToken) {
- grammarErrorOnNode(computedPropertyName.expression, Diagnostics.A_comma_expression_is_not_allowed_in_a_computed_property_name);
+ return grammarErrorOnNode(computedPropertyName.expression, Diagnostics.A_comma_expression_is_not_allowed_in_a_computed_property_name);
}
}
diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts
index 64511ad8072..f333520733e 100644
--- a/src/compiler/diagnosticInformationMap.generated.ts
+++ b/src/compiler/diagnosticInformationMap.generated.ts
@@ -299,6 +299,10 @@ module ts {
Type_0_is_not_an_array_type: { code: 2461, category: DiagnosticCategory.Error, key: "Type '{0}' is not an array type." },
A_rest_element_must_be_last_in_an_array_destructuring_pattern: { code: 2462, category: DiagnosticCategory.Error, key: "A rest element must be last in an array destructuring pattern" },
A_binding_pattern_parameter_cannot_be_optional_in_an_implementation_signature: { code: 2463, category: DiagnosticCategory.Error, key: "A binding pattern parameter cannot be optional in an implementation signature." },
+ A_computed_property_name_must_be_of_type_string_number_or_any: { code: 2464, category: DiagnosticCategory.Error, key: "A computed property name must be of type 'string', 'number', or 'any'." },
+ this_cannot_be_referenced_in_a_computed_property_name: { code: 2465, category: DiagnosticCategory.Error, key: "'this' cannot be referenced in a computed property name." },
+ super_cannot_be_referenced_in_a_computed_property_name: { code: 2466, category: DiagnosticCategory.Error, key: "'super' cannot be referenced in a computed property name." },
+ A_computed_property_name_cannot_reference_a_type_parameter_from_its_containing_type: { code: 2466, category: DiagnosticCategory.Error, key: "A computed property name cannot reference a type parameter from its containing type." },
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },
Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4004, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using private name '{1}'." },
@@ -448,6 +452,5 @@ module ts {
You_cannot_rename_this_element: { code: 8000, category: DiagnosticCategory.Error, key: "You cannot rename this element." },
yield_expressions_are_not_currently_supported: { code: 9000, category: DiagnosticCategory.Error, key: "'yield' expressions are not currently supported.", isEarly: true },
Generators_are_not_currently_supported: { code: 9001, category: DiagnosticCategory.Error, key: "Generators are not currently supported.", isEarly: true },
- Computed_property_names_are_not_currently_supported: { code: 9002, category: DiagnosticCategory.Error, key: "Computed property names are not currently supported.", isEarly: true },
};
}
\ No newline at end of file
diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json
index 6c33fa42013..49ee8eebcd9 100644
--- a/src/compiler/diagnosticMessages.json
+++ b/src/compiler/diagnosticMessages.json
@@ -675,7 +675,7 @@
},
"A parameter property may not be a binding pattern.": {
"category": "Error",
- "code": 1187
+ "code": 1187
},
"Duplicate identifier '{0}'.": {
@@ -1288,7 +1288,23 @@
},
"A binding pattern parameter cannot be optional in an implementation signature.": {
"category": "Error",
- "code": 2463
+ "code": 2463
+ },
+ "A computed property name must be of type 'string', 'number', or 'any'.": {
+ "category": "Error",
+ "code": 2464
+ },
+ "'this' cannot be referenced in a computed property name.": {
+ "category": "Error",
+ "code": 2465
+ },
+ "'super' cannot be referenced in a computed property name.": {
+ "category": "Error",
+ "code": 2466
+ },
+ "A computed property name cannot reference a type parameter from its containing type.": {
+ "category": "Error",
+ "code": 2466
},
"Import declaration '{0}' is using private name '{1}'.": {
@@ -1892,10 +1908,5 @@
"category": "Error",
"code": 9001,
"isEarly": true
- },
- "Computed property names are not currently supported.": {
- "category": "Error",
- "code": 9002,
- "isEarly": true
}
}
diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts
index dafd03717a6..34978ed7fd6 100644
--- a/src/compiler/emitter.ts
+++ b/src/compiler/emitter.ts
@@ -932,6 +932,10 @@ module ts {
}
function emitPropertyDeclaration(node: Declaration) {
+ if (hasDynamicName(node)) {
+ return;
+ }
+
emitJsDocComments(node);
emitClassMemberDeclarationFlags(node);
emitVariableDeclaration(node);
@@ -939,11 +943,13 @@ module ts {
writeLine();
}
- // TODO(jfreeman): Factor out common part of property definition, but treat name differently
function emitVariableDeclaration(node: VariableDeclaration) {
// If we are emitting property it isn't moduleElement and hence we already know it needs to be emitted
// so there is no check needed to see if declaration is visible
if (node.kind !== SyntaxKind.VariableDeclaration || resolver.isDeclarationVisible(node)) {
+ // If this node is a computed name, it can only be a symbol, because we've already skipped
+ // it if it's not a well known symbol. In that case, the text of the name will be exactly
+ // what we want, namely the name expression enclosed in brackets.
writeTextOfNode(currentSourceFile, node.name);
// If optional property emit ?
if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && hasQuestionToken(node)) {
@@ -1030,6 +1036,10 @@ module ts {
}
function emitAccessorDeclaration(node: AccessorDeclaration) {
+ if (hasDynamicName(node)) {
+ return;
+ }
+
var accessors = getAllAccessorDeclarations(node.parent, node);
if (node === accessors.firstAccessor) {
emitJsDocComments(accessors.getAccessor);
@@ -1107,6 +1117,10 @@ module ts {
}
function emitFunctionDeclaration(node: FunctionLikeDeclaration) {
+ if (hasDynamicName(node)) {
+ return;
+ }
+
// If we are emitting Method/Constructor it isn't moduleElement and hence already determined to be emitting
// so no need to verify if the declaration is visible
if ((node.kind !== SyntaxKind.FunctionDeclaration || resolver.isDeclarationVisible(node)) &&
@@ -1723,7 +1737,14 @@ module ts {
if (scopeName) {
var parentIndex = getSourceMapNameIndex();
if (parentIndex !== -1) {
- scopeName = sourceMapData.sourceMapNames[parentIndex] + "." + scopeName;
+ // Child scopes are always shown with a dot (even if they have no name),
+ // unless it is a computed property. Then it is shown with brackets,
+ // but the brackets are included in the name.
+ var name = (node).name;
+ if (!name || name.kind !== SyntaxKind.ComputedPropertyName) {
+ scopeName = "." + scopeName;
+ }
+ scopeName = sourceMapData.sourceMapNames[parentIndex] + scopeName;
}
scopeNameIndex = getProperty(sourceMapNameIndexMap, scopeName);
@@ -1751,8 +1772,11 @@ module ts {
node.kind === SyntaxKind.EnumDeclaration) {
// Declaration and has associated name use it
if ((node).name) {
- // TODO(jfreeman): Ask shkamat about what this name should be for source maps
- scopeName = ((node).name).text;
+ var name = (node).name;
+ // For computed property names, the text will include the brackets
+ scopeName = name.kind === SyntaxKind.ComputedPropertyName
+ ? getTextOfNode(name)
+ : ((node).name).text;
}
recordScopeNameStart(scopeName);
}
@@ -2403,28 +2427,20 @@ module ts {
}
function emitMethod(node: MethodDeclaration) {
- if (!isObjectLiteralMethod(node)) {
- return;
- }
- emitLeadingComments(node);
emit(node.name);
if (languageVersion < ScriptTarget.ES6) {
write(": function ");
}
emitSignatureAndBody(node);
- emitTrailingComments(node);
}
function emitPropertyAssignment(node: PropertyDeclaration) {
- emitLeadingComments(node);
emit(node.name);
write(": ");
emit(node.initializer);
- emitTrailingComments(node);
}
function emitShorthandPropertyAssignment(node: ShorthandPropertyAssignment) {
- emitLeadingComments(node);
emit(node.name);
// If short-hand property has a prefix, then regardless of the target version, we will emit it as normal property assignment. For example:
// module m {
@@ -2441,7 +2457,6 @@ module ts {
// Short-hand, { x }, is equivalent of normal form { x: x }
emitExpressionIdentifier(node.name);
}
- emitTrailingComments(node);
}
function tryEmitConstantValue(node: PropertyAccessExpression | ElementAccessExpression): boolean {
@@ -2661,14 +2676,11 @@ module ts {
}
function emitExpressionStatement(node: ExpressionStatement) {
- emitLeadingComments(node);
emitParenthesized(node.expression, /*parenthesized*/ node.expression.kind === SyntaxKind.ArrowFunction);
write(";");
- emitTrailingComments(node);
}
function emitIfStatement(node: IfStatement) {
- emitLeadingComments(node);
var endPos = emitToken(SyntaxKind.IfKeyword, node.pos);
write(" ");
endPos = emitToken(SyntaxKind.OpenParenToken, endPos);
@@ -2686,7 +2698,6 @@ module ts {
emitEmbeddedStatement(node.elseStatement);
}
}
- emitTrailingComments(node);
}
function emitDoStatement(node: DoStatement) {
@@ -2774,11 +2785,9 @@ module ts {
}
function emitReturnStatement(node: ReturnStatement) {
- emitLeadingComments(node);
emitToken(SyntaxKind.ReturnKeyword, node.pos);
emitOptional(" ", node.expression);
write(";");
- emitTrailingComments(node);
}
function emitWithStatement(node: WhileStatement) {
@@ -3102,7 +3111,6 @@ module ts {
}
function emitVariableDeclaration(node: VariableDeclaration) {
- emitLeadingComments(node);
if (isBindingPattern(node.name)) {
if (languageVersion < ScriptTarget.ES6) {
emitDestructuring(node);
@@ -3116,11 +3124,9 @@ module ts {
emitModuleMemberName(node);
emitOptional(" = ", node.initializer);
}
- emitTrailingComments(node);
}
function emitVariableStatement(node: VariableStatement) {
- emitLeadingComments(node);
if (!(node.flags & NodeFlags.Export)) {
if (isLet(node.declarationList)) {
write("let ");
@@ -3134,11 +3140,9 @@ module ts {
}
emitCommaList(node.declarationList.declarations);
write(";");
- emitTrailingComments(node);
}
function emitParameter(node: ParameterDeclaration) {
- emitLeadingComments(node);
if (languageVersion < ScriptTarget.ES6) {
if (isBindingPattern(node.name)) {
var name = createTempVariable(node);
@@ -3159,7 +3163,6 @@ module ts {
emit(node.name);
emitOptional(" = ", node.initializer);
}
- emitTrailingComments(node);
}
function emitDefaultValueAssignments(node: FunctionLikeDeclaration) {
@@ -3232,11 +3235,9 @@ module ts {
}
function emitAccessor(node: AccessorDeclaration) {
- emitLeadingComments(node);
write(node.kind === SyntaxKind.GetAccessor ? "get " : "set ");
emit(node.name);
emitSignatureAndBody(node);
- emitTrailingComments(node);
}
function emitFunctionDeclaration(node: FunctionLikeDeclaration) {
@@ -3306,7 +3307,10 @@ module ts {
write(" ");
emitStart(node.body);
write("return ");
- emitNode(node.body);
+
+ // Don't emit comments on this body. We'll have already taken care of it above
+ // when we called emitDetachedComments.
+ emitNode(node.body, /*disableComments:*/ true);
emitEnd(node.body);
write(";");
emitTempDeclarations(/*newLine*/ false);
@@ -3323,7 +3327,7 @@ module ts {
writeLine();
emitLeadingComments(node.body);
write("return ");
- emit(node.body);
+ emit(node.body, /*disableComments:*/ true);
write(";");
emitTrailingComments(node.body);
}
@@ -3504,7 +3508,6 @@ module ts {
}
function emitClassDeclaration(node: ClassDeclaration) {
- emitLeadingComments(node);
write("var ");
emit(node.name);
write(" = (function (");
@@ -3554,7 +3557,6 @@ module ts {
emitEnd(node);
write(";");
}
- emitTrailingComments(node);
function emitConstructorOfClass() {
var saveTempCount = tempCount;
@@ -3633,13 +3635,17 @@ module ts {
emitPinnedOrTripleSlashComments(node);
}
+ function shouldEmitEnumDeclaration(node: EnumDeclaration) {
+ var isConstEnum = isConst(node);
+ return !isConstEnum || compilerOptions.preserveConstEnums;
+ }
+
function emitEnumDeclaration(node: EnumDeclaration) {
// const enums are completely erased during compilation.
- var isConstEnum = isConst(node);
- if (isConstEnum && !compilerOptions.preserveConstEnums) {
+ if (!shouldEmitEnumDeclaration(node)) {
return;
}
- emitLeadingComments(node);
+
if (!(node.flags & NodeFlags.Export)) {
emitStart(node);
write("var ");
@@ -3656,7 +3662,7 @@ module ts {
write(") {");
increaseIndent();
scopeEmitStart(node);
- emitEnumMemberDeclarations(isConstEnum);
+ emitLines(node.members);
decreaseIndent();
writeLine();
emitToken(SyntaxKind.CloseBraceToken, node.members.end);
@@ -3677,32 +3683,27 @@ module ts {
emitEnd(node);
write(";");
}
- emitTrailingComments(node);
+ }
- function emitEnumMemberDeclarations(isConstEnum: boolean) {
- forEach(node.members, member => {
- writeLine();
- emitLeadingComments(member);
- emitStart(member);
- write(resolver.getLocalNameOfContainer(node));
- write("[");
- write(resolver.getLocalNameOfContainer(node));
- write("[");
- emitExpressionForPropertyName(member.name);
- write("] = ");
- if (member.initializer && !isConstEnum) {
- emit(member.initializer);
- }
- else {
- write(resolver.getEnumMemberValue(member).toString());
- }
- write("] = ");
- emitExpressionForPropertyName(member.name);
- emitEnd(member);
- write(";");
- emitTrailingComments(member);
- });
+ function emitEnumMember(node: EnumMember) {
+ var enumParent = node.parent;
+ emitStart(node);
+ write(resolver.getLocalNameOfContainer(enumParent));
+ write("[");
+ write(resolver.getLocalNameOfContainer(enumParent));
+ write("[");
+ emitExpressionForPropertyName(node.name);
+ write("] = ");
+ if (node.initializer && !isConst(enumParent)) {
+ emit(node.initializer);
}
+ else {
+ write(resolver.getEnumMemberValue(node).toString());
+ }
+ write("] = ");
+ emitExpressionForPropertyName(node.name);
+ emitEnd(node);
+ write(";");
}
function getInnerMostModuleDeclarationFromDottedModule(moduleDeclaration: ModuleDeclaration): ModuleDeclaration {
@@ -3712,14 +3713,18 @@ module ts {
}
}
+ function shouldEmitModuleDeclaration(node: ModuleDeclaration) {
+ return isInstantiatedModule(node, compilerOptions.preserveConstEnums);
+ }
+
function emitModuleDeclaration(node: ModuleDeclaration) {
// Emit only if this module is non-ambient.
- var shouldEmit = isInstantiatedModule(node, compilerOptions.preserveConstEnums);
+ var shouldEmit = shouldEmitModuleDeclaration(node);
if (!shouldEmit) {
return emitPinnedOrTripleSlashComments(node);
}
- emitLeadingComments(node);
+
emitStart(node);
write("var ");
emit(node.name);
@@ -3764,7 +3769,6 @@ module ts {
emitModuleMemberName(node);
write(" = {}));");
emitEnd(node);
- emitTrailingComments(node);
}
function emitImportDeclaration(node: ImportDeclaration) {
@@ -3954,7 +3958,7 @@ module ts {
emitLeadingComments(node.endOfFileToken);
}
- function emitNode(node: Node): void {
+ function emitNode(node: Node, disableComments?:boolean): void {
if (!node) {
return;
}
@@ -3962,6 +3966,46 @@ module ts {
if (node.flags & NodeFlags.Ambient) {
return emitPinnedOrTripleSlashComments(node);
}
+
+ var emitComments = !disableComments && shouldEmitLeadingAndTrailingComments(node);
+ if (emitComments) {
+ emitLeadingComments(node);
+ }
+
+ emitJavaScriptWorker(node);
+
+ if (emitComments) {
+ emitTrailingComments(node);
+ }
+ }
+
+ function shouldEmitLeadingAndTrailingComments(node: Node) {
+ switch (node.kind) {
+ // All of these entities are emitted in a specialized fashion. As such, we allow
+ // the specilized methods for each to handle the comments on the nodes.
+ case SyntaxKind.InterfaceDeclaration:
+ case SyntaxKind.FunctionDeclaration:
+ case SyntaxKind.ImportDeclaration:
+ case SyntaxKind.TypeAliasDeclaration:
+ case SyntaxKind.ExportAssignment:
+ return false;
+
+ case SyntaxKind.ModuleDeclaration:
+ // Only emit the leading/trailing comments for a module if we're actually
+ // emitting the module as well.
+ return shouldEmitModuleDeclaration(node);
+
+ case SyntaxKind.EnumDeclaration:
+ // Only emit the leading/trailing comments for an enum if we're actually
+ // emitting the module as well.
+ return shouldEmitEnumDeclaration(node);
+ }
+
+ // Emit comments for everything else.
+ return true;
+ }
+
+ function emitJavaScriptWorker(node: Node) {
// Check if the node can be emitted regardless of the ScriptTarget
switch (node.kind) {
case SyntaxKind.Identifier:
@@ -4099,6 +4143,8 @@ module ts {
return emitInterfaceDeclaration(node);
case SyntaxKind.EnumDeclaration:
return emitEnumDeclaration(node);
+ case SyntaxKind.EnumMember:
+ return emitEnumMember(node);
case SyntaxKind.ModuleDeclaration:
return emitModuleDeclaration(node);
case SyntaxKind.ImportDeclaration:
@@ -4128,17 +4174,19 @@ module ts {
function getLeadingCommentsToEmit(node: Node) {
// Emit the leading comments only if the parent's pos doesn't match because parent should take care of emitting these comments
- if (node.parent.kind === SyntaxKind.SourceFile || node.pos !== node.parent.pos) {
- var leadingComments: CommentRange[];
- if (hasDetachedComments(node.pos)) {
- // get comments without detached comments
- leadingComments = getLeadingCommentsWithoutDetachedComments();
+ if (node.parent) {
+ if (node.parent.kind === SyntaxKind.SourceFile || node.pos !== node.parent.pos) {
+ var leadingComments: CommentRange[];
+ if (hasDetachedComments(node.pos)) {
+ // get comments without detached comments
+ leadingComments = getLeadingCommentsWithoutDetachedComments();
+ }
+ else {
+ // get the leading comments from the node
+ leadingComments = getLeadingCommentRangesOfNode(node, currentSourceFile);
+ }
+ return leadingComments;
}
- else {
- // get the leading comments from the node
- leadingComments = getLeadingCommentRangesOfNode(node, currentSourceFile);
- }
- return leadingComments;
}
}
@@ -4151,10 +4199,12 @@ module ts {
function emitTrailingDeclarationComments(node: Node) {
// Emit the trailing comments only if the parent's end doesn't match
- if (node.parent.kind === SyntaxKind.SourceFile || node.end !== node.parent.end) {
- var trailingComments = getTrailingCommentRanges(currentSourceFile.text, node.end);
- // trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/
- emitComments(currentSourceFile, writer, trailingComments, /*trailingSeparator*/ false, newLine, writeComment);
+ if (node.parent) {
+ if (node.parent.kind === SyntaxKind.SourceFile || node.end !== node.parent.end) {
+ var trailingComments = getTrailingCommentRanges(currentSourceFile.text, node.end);
+ // trailing comments are emitted at space/*trailing comment1 */space/*trailing comment*/
+ emitComments(currentSourceFile, writer, trailingComments, /*trailingSeparator*/ false, newLine, writeComment);
+ }
}
}
diff --git a/src/compiler/types.ts b/src/compiler/types.ts
index b8c842641d7..80bdc875177 100644
--- a/src/compiler/types.ts
+++ b/src/compiler/types.ts
@@ -330,6 +330,12 @@ module ts {
HasAggregatedChildData = 1 << 6
}
+ export const enum RelationComparisonResult {
+ Succeeded = 1, // Should be truthy
+ Failed = 2,
+ FailedAndReported = 3
+ }
+
export interface Node extends TextRange {
kind: SyntaxKind;
flags: NodeFlags;
@@ -1266,29 +1272,33 @@ module ts {
}
export const enum TypeFlags {
- Any = 0x00000001,
- String = 0x00000002,
- Number = 0x00000004,
- Boolean = 0x00000008,
- Void = 0x00000010,
- Undefined = 0x00000020,
- Null = 0x00000040,
- Enum = 0x00000080, // Enum type
- StringLiteral = 0x00000100, // String literal type
- TypeParameter = 0x00000200, // Type parameter
- Class = 0x00000400, // Class
- Interface = 0x00000800, // Interface
- Reference = 0x00001000, // Generic type reference
- Tuple = 0x00002000, // Tuple
- Union = 0x00004000, // Union
- Anonymous = 0x00008000, // Anonymous
- FromSignature = 0x00010000, // Created for signature assignment check
- Unwidened = 0x00020000, // Unwidened type (is or contains Undefined or Null type)
+ Any = 0x00000001,
+ String = 0x00000002,
+ Number = 0x00000004,
+ Boolean = 0x00000008,
+ Void = 0x00000010,
+ Undefined = 0x00000020,
+ Null = 0x00000040,
+ Enum = 0x00000080, // Enum type
+ StringLiteral = 0x00000100, // String literal type
+ TypeParameter = 0x00000200, // Type parameter
+ Class = 0x00000400, // Class
+ Interface = 0x00000800, // Interface
+ Reference = 0x00001000, // Generic type reference
+ Tuple = 0x00002000, // Tuple
+ Union = 0x00004000, // Union
+ Anonymous = 0x00008000, // Anonymous
+ FromSignature = 0x00010000, // Created for signature assignment check
+ ObjectLiteral = 0x00020000, // Originates in an object literal
+ ContainsUndefinedOrNull = 0x00040000, // Type is or contains Undefined or Null type
+ ContainsObjectLiteral = 0x00080000, // Type is or contains object literal type
Intrinsic = Any | String | Number | Boolean | Void | Undefined | Null,
+ Primitive = String | Number | Boolean | Void | Undefined | Null | StringLiteral | Enum,
StringLike = String | StringLiteral,
NumberLike = Number | Enum,
ObjectType = Class | Interface | Reference | Tuple | Anonymous,
+ RequiresWidening = ContainsUndefinedOrNull | ContainsObjectLiteral
}
// Properties common to all types
diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts
index 7494ec9f6cb..6c894ad7d9c 100644
--- a/src/compiler/utilities.ts
+++ b/src/compiler/utilities.ts
@@ -399,6 +399,21 @@ module ts {
return undefined;
}
switch (node.kind) {
+ case SyntaxKind.ComputedPropertyName:
+ // If the grandparent node is an object literal (as opposed to a class),
+ // then the computed property is not a 'this' container.
+ // A computed property name in a class needs to be a this container
+ // so that we can error on it.
+ if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) {
+ return node;
+ }
+ // If this is a computed property, then the parent should not
+ // make it a this container. The parent might be a property
+ // in an object literal, like a method or accessor. But in order for
+ // such a parent to be a this container, the reference must be in
+ // the *body* of the container.
+ node = node.parent;
+ break;
case SyntaxKind.ArrowFunction:
if (!includeArrowFunctions) {
continue;
@@ -421,13 +436,32 @@ module ts {
}
}
- export function getSuperContainer(node: Node): Node {
+ export function getSuperContainer(node: Node, includeFunctions: boolean): Node {
while (true) {
node = node.parent;
- if (!node) {
- return undefined;
- }
+ if (!node) return node;
switch (node.kind) {
+ case SyntaxKind.ComputedPropertyName:
+ // If the grandparent node is an object literal (as opposed to a class),
+ // then the computed property is not a 'super' container.
+ // A computed property name in a class needs to be a super container
+ // so that we can error on it.
+ if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) {
+ return node;
+ }
+ // If this is a computed property, then the parent should not
+ // make it a super container. The parent might be a property
+ // in an object literal, like a method or accessor. But in order for
+ // such a parent to be a super container, the reference must be in
+ // the *body* of the container.
+ node = node.parent;
+ break;
+ case SyntaxKind.FunctionDeclaration:
+ case SyntaxKind.FunctionExpression:
+ case SyntaxKind.ArrowFunction:
+ if (!includeFunctions) {
+ continue;
+ }
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
case SyntaxKind.MethodDeclaration:
@@ -527,6 +561,8 @@ module ts {
return node === (parent).expression;
case SyntaxKind.TemplateSpan:
return node === (parent).expression;
+ case SyntaxKind.ComputedPropertyName:
+ return node === (parent).expression;
default:
if (isExpression(parent)) {
return true;
diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts
index 232411d03d9..5d32f87ff57 100644
--- a/src/harness/fourslash.ts
+++ b/src/harness/fourslash.ts
@@ -548,6 +548,18 @@ module FourSlash {
}
}
+ public verifyGetEmitOutputForCurrentFile(expected: string): void {
+ var emit = this.languageService.getEmitOutput(this.activeFile.fileName);
+ if (emit.outputFiles.length !== 1) {
+ throw new Error("Expected exactly one output from emit of " + this.activeFile.fileName);
+ }
+ this.taoInvalidReason = 'verifyGetEmitOutputForCurrentFile impossible';
+ var actual = emit.outputFiles[0].text;
+ if (actual !== expected) {
+ this.raiseError("Expected emit output to be '" + expected + "', but got '" + actual + "'");
+ }
+ }
+
public verifyMemberListContains(symbol: string, text?: string, documentation?: string, kind?: string) {
this.scenarioActions.push('');
this.scenarioActions.push('');
diff --git a/src/services/compiler/diagnostics.ts b/src/services/compiler/diagnostics.ts
deleted file mode 100644
index 5114f83f9e5..00000000000
--- a/src/services/compiler/diagnostics.ts
+++ /dev/null
@@ -1,27 +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.
-//
-
-///
-
-module TypeScript {
- export interface Logger {
- log(s: string): void;
- }
-
- export class NullLogger implements Logger {
- public log(s: string): void {
- }
- }
-}
\ No newline at end of file
diff --git a/src/services/compiler/emitter.ts b/src/services/compiler/emitter.ts
deleted file mode 100644
index 8de5e64dbba..00000000000
--- a/src/services/compiler/emitter.ts
+++ /dev/null
@@ -1,3797 +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.
-//
-
-///
-
-module TypeScript {
- export enum EmitContainer {
- Prog,
- Module,
- DynamicModule,
- Class,
- Constructor,
- Function,
- Args,
- Interface,
- }
-
- export class EmitState {
- public column: number;
- public line: number;
- public container: EmitContainer;
-
- constructor() {
- this.column = 0;
- this.line = 0;
- this.container = EmitContainer.Prog;
- }
- }
-
- export class EmitOptions {
- private _diagnostic: Diagnostic = null;
-
- private _settings: ImmutableCompilationSettings = null;
- private _commonDirectoryPath = "";
- private _sharedOutputFile = "";
- private _sourceRootDirectory = "";
- private _sourceMapRootDirectory = "";
- private _outputDirectory = "";
-
- public diagnostic(): Diagnostic { return this._diagnostic; }
-
- public commonDirectoryPath() { return this._commonDirectoryPath; }
- public sharedOutputFile() { return this._sharedOutputFile; }
- public sourceRootDirectory() { return this._sourceRootDirectory; }
- public sourceMapRootDirectory() { return this._sourceMapRootDirectory; }
- public outputDirectory() { return this._outputDirectory; }
-
- public compilationSettings() { return this._settings; }
-
- constructor(compiler: TypeScriptCompiler, public resolvePath: (path: string) => string) {
- var settings = compiler.compilationSettings();
- this._settings = settings;
-
- // If the document is an external module, then report if the the user has not
- // provided the right command line option.
- if (settings.moduleGenTarget() === ModuleGenTarget.Unspecified) {
- var fileNames = compiler.fileNames();
- for (var i = 0, n = fileNames.length; i < n; i++) {
- var document = compiler.getDocument(fileNames[i]);
- if (!document.isDeclareFile() && document.syntaxTree().isExternalModule()) {
- var errorSpan = externalModuleIndicatorSpan(document.syntaxTree());
- this._diagnostic = new Diagnostic(document.fileName, document.lineMap(), errorSpan.start(), errorSpan.length(),
- DiagnosticCode.Cannot_compile_external_modules_unless_the_module_flag_is_provided);
-
- return;
- }
- }
- }
-
- if (!settings.mapSourceFiles()) {
- // Error to specify --mapRoot or --sourceRoot without mapSourceFiles
- if (settings.mapRoot()) {
- if (settings.sourceRoot()) {
- this._diagnostic = new Diagnostic(null, null, 0, 0, DiagnosticCode.Options_mapRoot_and_sourceRoot_cannot_be_specified_without_specifying_sourcemap_option, null);
- return;
- }
- else {
- this._diagnostic = new Diagnostic(null, null, 0, 0, DiagnosticCode.Option_mapRoot_cannot_be_specified_without_specifying_sourcemap_option, null);
- return;
- }
- }
- else if (settings.sourceRoot()) {
- this._diagnostic = new Diagnostic(null, null, 0, 0, DiagnosticCode.Option_sourceRoot_cannot_be_specified_without_specifying_sourcemap_option, null);
- return;
- }
- }
-
- this._sourceMapRootDirectory = convertToDirectoryPath(switchToForwardSlashes(settings.mapRoot()));
- this._sourceRootDirectory = convertToDirectoryPath(switchToForwardSlashes(settings.sourceRoot()));
-
- if (settings.outFileOption() ||
- settings.outDirOption() ||
- settings.mapRoot() ||
- settings.sourceRoot()) {
-
- if (settings.outFileOption()) {
- this._sharedOutputFile = switchToForwardSlashes(resolvePath(settings.outFileOption()));
- }
-
- if (settings.outDirOption()) {
- this._outputDirectory = convertToDirectoryPath(switchToForwardSlashes(resolvePath(settings.outDirOption())));
- }
-
- // Parse the directory structure
- if (this._outputDirectory || this._sourceMapRootDirectory || this.sourceRootDirectory) {
- this.determineCommonDirectoryPath(compiler);
- }
- }
- }
-
- private determineCommonDirectoryPath(compiler: TypeScriptCompiler): void {
- var commonComponents: string[] = [];
- var commonComponentsLength = -1;
-
- var fileNames = compiler.fileNames();
- for (var i = 0, len = fileNames.length; i < len; i++) {
- var fileName = fileNames[i];
- var document = compiler.getDocument(fileNames[i]);
- var sourceUnit = document.sourceUnit();
-
- if (!document.isDeclareFile()) {
- var fileComponents = filePathComponents(fileName);
- if (commonComponentsLength === -1) {
- // First time at finding common path
- // So common path = directory of file
- commonComponents = fileComponents;
- commonComponentsLength = commonComponents.length;
- }
- else {
- var updatedPath = false;
- for (var j = 0; j < commonComponentsLength && j < fileComponents.length; j++) {
- if (commonComponents[j] !== fileComponents[j]) {
- // The new components = 0 ... j -1
- commonComponentsLength = j;
- updatedPath = true;
-
- if (j === 0) {
- var isDynamicModuleCompilation = ArrayUtilities.any(fileNames, fileName => {
- document = compiler.getDocument(fileName);
- return !document.isDeclareFile() && document.syntaxTree().isExternalModule();
- });
-
- if (this._outputDirectory || // there is --outDir specified
- this._sourceRootDirectory || // there is --sourceRoot specified
- (this._sourceMapRootDirectory && // there is --map Specified and there would be multiple js files generated
- (!this._sharedOutputFile || isDynamicModuleCompilation))) {
- // Its error to not have common path
- this._diagnostic = new Diagnostic(null, null, 0, 0, DiagnosticCode.Cannot_find_the_common_subdirectory_path_for_the_input_files, null);
- return;
- }
-
- return;
- }
-
- break;
- }
- }
-
- // If the fileComponent path completely matched and less than already found update the length
- if (!updatedPath && fileComponents.length < commonComponentsLength) {
- commonComponentsLength = fileComponents.length;
- }
- }
- }
- }
-
- this._commonDirectoryPath = commonComponents.slice(0, commonComponentsLength).join("/") + "/";
- }
- }
-
- export class Indenter {
- static indentStep: number = 4;
- static indentStepString: string = " ";
- static indentStrings: string[] = [];
- public indentAmt: number = 0;
-
- public increaseIndent() {
- this.indentAmt += Indenter.indentStep;
- }
-
- public decreaseIndent() {
- this.indentAmt -= Indenter.indentStep;
- }
-
- public getIndent() {
- var indentString = Indenter.indentStrings[this.indentAmt];
- if (indentString === undefined) {
- indentString = "";
- for (var i = 0; i < this.indentAmt; i = i + Indenter.indentStep) {
- indentString += Indenter.indentStepString;
- }
- Indenter.indentStrings[this.indentAmt] = indentString;
- }
- return indentString;
- }
- }
-
- export function lastParameterIsRest(parameters: ParameterSyntax[]): boolean {
- return parameters.length > 0 && (parameters[parameters.length - 1]).dotDotDotToken !== null;
- }
-
- export class Emitter {
- public globalThisCapturePrologueEmitted = false;
- public extendsPrologueEmitted = false;
- public thisClassNode: ClassDeclarationSyntax = null;
- public inArrowFunction: boolean = false;
- public moduleName = "";
- public emitState = new EmitState();
- public indenter = new Indenter();
- public sourceMapper: SourceMapper = null;
- public captureThisStmtString = "var _this = this;";
- private currentVariableDeclaration: VariableDeclarationSyntax;
- private declStack: PullDecl[] = [];
- private exportAssignment: ExportAssignmentSyntax = null;
- private inWithBlock = false;
-
- public document: Document = null;
-
- // If we choose to detach comments from an element (for example, the Copyright comments),
- // then keep track of that element so that we don't emit all on the comments on it when
- // we visit it.
- private detachedCommentsElement: ISyntaxElement = null;
-
- constructor(public emittingFileName: string,
- public outfile: TextWriter,
- public emitOptions: EmitOptions,
- private semanticInfoChain: SemanticInfoChain) {
- }
-
- private pushDecl(decl: PullDecl) {
- if (decl) {
- this.declStack[this.declStack.length] = decl;
- }
- }
-
- private popDecl(decl: PullDecl) {
- if (decl) {
- this.declStack.length--;
- }
- }
-
- private getEnclosingDecl() {
- var declStackLen = this.declStack.length;
- var enclosingDecl = declStackLen > 0 ? this.declStack[declStackLen - 1] : null;
- return enclosingDecl;
- }
-
- public setExportAssignment(exportAssignment: ExportAssignmentSyntax) {
- this.exportAssignment = exportAssignment;
- }
-
- public getExportAssignment() {
- return this.exportAssignment;
- }
-
- public setDocument(document: Document) {
- this.document = document;
- }
-
- public shouldEmitImportDeclaration(importDeclAST: ImportDeclarationSyntax) {
- var isExternalModuleReference = importDeclAST.moduleReference.kind() === SyntaxKind.ExternalModuleReference;
- var importDecl = this.semanticInfoChain.getDeclForAST(importDeclAST);
- var isExported = hasFlag(importDecl.flags, PullElementFlags.Exported);
- var isAmdCodeGen = this.emitOptions.compilationSettings().moduleGenTarget() === ModuleGenTarget.Asynchronous;
-
- // 1) Any internal reference needs to check if the emit can happen
- // 2) External module reference with export modifier always needs to be emitted
- // 3) commonjs needs the var declaration for the import declaration
- if (isExternalModuleReference && !isExported && isAmdCodeGen) {
- return false;
- }
-
- var importSymbol = importDecl.getSymbol(this.semanticInfoChain);
- if (importSymbol.isUsedAsValue()) {
- return true;
- }
-
- if (importDeclAST.moduleReference.kind() !== SyntaxKind.ExternalModuleReference) {
- var canBeUsedExternally = isExported || importSymbol.typeUsedExternally() || importSymbol.isUsedInExportedAlias();
- if (!canBeUsedExternally && !this.document.syntaxTree().isExternalModule()) {
- // top level import in non-external module are visible across the whole global module
- canBeUsedExternally = hasFlag(importDecl.getParentDecl().kind, PullElementKind.Script | PullElementKind.DynamicModule);
- }
-
- if (canBeUsedExternally) {
- if (importSymbol.getExportAssignedValueSymbol()) {
- return true;
- }
-
- var containerSymbol = importSymbol.getExportAssignedContainerSymbol();
- if (containerSymbol && containerSymbol.getInstanceSymbol()) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- public emitImportDeclaration(importDeclAST: ImportDeclarationSyntax) {
- var isExternalModuleReference = importDeclAST.moduleReference.kind() === SyntaxKind.ExternalModuleReference;
- var importDecl = this.semanticInfoChain.getDeclForAST(importDeclAST);
- var isExported = hasFlag(importDecl.flags, PullElementFlags.Exported);
- var isAmdCodeGen = this.emitOptions.compilationSettings().moduleGenTarget() === ModuleGenTarget.Asynchronous;
-
- this.emitComments(importDeclAST, true);
-
- var importSymbol = importDecl.getSymbol(this.semanticInfoChain);
-
- var parentSymbol = importSymbol.getContainer();
- var parentKind = parentSymbol ? parentSymbol.kind : PullElementKind.None;
- var associatedParentSymbol = parentSymbol ? parentSymbol.getAssociatedContainerType() : null;
- var associatedParentSymbolKind = associatedParentSymbol ? associatedParentSymbol.kind : PullElementKind.None;
-
- var needsPropertyAssignment = false;
- var usePropertyAssignmentInsteadOfVarDecl = false;
- var moduleNamePrefix: string;
-
- if (isExported &&
- (parentKind === PullElementKind.Container ||
- parentKind === PullElementKind.DynamicModule ||
- associatedParentSymbolKind === PullElementKind.Container ||
- associatedParentSymbolKind === PullElementKind.DynamicModule)) {
- if (importSymbol.getExportAssignedTypeSymbol() || importSymbol.getExportAssignedContainerSymbol()) {
- // Type or container assignment that is exported
- needsPropertyAssignment = true;
- }
- else {
- var valueSymbol = importSymbol.getExportAssignedValueSymbol();
- if (valueSymbol &&
- (valueSymbol.kind === PullElementKind.Method || valueSymbol.kind === PullElementKind.Function)) {
- needsPropertyAssignment = true;
- }
- else {
- usePropertyAssignmentInsteadOfVarDecl = true;
- }
- }
-
- // Calculate what name prefix to use
- if (this.emitState.container === EmitContainer.DynamicModule) {
- moduleNamePrefix = "exports."
- }
- else {
- moduleNamePrefix = this.moduleName + ".";
- }
- }
-
- if (isAmdCodeGen && isExternalModuleReference) {
- // For amdCode gen of exported external module reference, do not emit var declaration
- // Emit the property assignment since it is exported
- needsPropertyAssignment = true;
- }
- else {
- this.recordSourceMappingStart(importDeclAST);
- if (usePropertyAssignmentInsteadOfVarDecl) {
- this.writeToOutput(moduleNamePrefix);
- }
- else {
- this.writeToOutput("var ");
- }
- this.writeToOutput(importDeclAST.identifier.text() + " = ");
- var aliasAST = importDeclAST.moduleReference;
-
- if (isExternalModuleReference) {
- this.writeToOutput("require(" + (aliasAST).stringLiteral.text() + ")");
- }
- else {
- this.emitJavascript((aliasAST).moduleName, false);
- }
-
- this.recordSourceMappingEnd(importDeclAST);
- this.writeToOutput(";");
-
- if (needsPropertyAssignment) {
- this.writeLineToOutput("");
- this.emitIndent();
- }
- }
-
- if (needsPropertyAssignment) {
- this.writeToOutputWithSourceMapRecord(moduleNamePrefix + importDeclAST.identifier.text() + " = " + importDeclAST.identifier.text(), importDeclAST);
- this.writeToOutput(";");
- }
- this.emitComments(importDeclAST, false);
- }
-
- public createSourceMapper(document: Document, jsFileName: string, jsFile: TextWriter, sourceMapOut: TextWriter, resolvePath: (path: string) => string) {
- this.sourceMapper = new SourceMapper(jsFile, sourceMapOut, document, jsFileName, this.emitOptions, resolvePath);
- }
-
- public setSourceMapperNewSourceFile(document: Document) {
- this.sourceMapper.setNewSourceFile(document, this.emitOptions);
- }
-
- private updateLineAndColumn(s: string) {
- var lineNumbers = TextUtilities.parseLineStarts(s);
- if (lineNumbers.length > 1) {
- // There are new lines in the string, update the line and column number accordingly
- this.emitState.line += lineNumbers.length - 1;
- this.emitState.column = s.length - lineNumbers[lineNumbers.length - 1];
- }
- else {
- // No new lines in the string
- this.emitState.column += s.length;
- }
- }
-
- public writeToOutputWithSourceMapRecord(s: string, astSpan: ISyntaxElement) {
- if (astSpan) {
- this.recordSourceMappingStart(astSpan);
- }
-
- this.writeToOutput(s);
-
- if (astSpan) {
- this.recordSourceMappingEnd(astSpan);
- }
- }
-
- public writeToOutput(s: string) {
- this.outfile.Write(s);
- this.updateLineAndColumn(s);
- }
-
- public writeLineToOutput(s: string, force = false) {
- // No need to print a newline if we're already at the start of the line.
- if (!force && s === "" && this.emitState.column === 0) {
- return;
- }
-
- this.outfile.WriteLine(s);
- this.updateLineAndColumn(s);
- this.emitState.column = 0;
- this.emitState.line++;
- }
-
- public writeCaptureThisStatement(ast: ISyntaxElement) {
- this.emitIndent();
- this.writeToOutputWithSourceMapRecord(this.captureThisStmtString, ast);
- this.writeLineToOutput("");
- }
-
- public setContainer(c: number): number {
- var temp = this.emitState.container;
- this.emitState.container = c;
- return temp;
- }
-
- private getIndentString() {
- return this.indenter.getIndent();
- }
-
- public emitIndent() {
- this.writeToOutput(this.getIndentString());
- }
-
- public emitComment(comment: Comment, trailing: boolean, first: boolean, noLeadingSpace = false) {
- if (this.emitOptions.compilationSettings().removeComments()) {
- return;
- }
-
- var text = getTrimmedTextLines(comment);
- var emitColumn = this.emitState.column;
-
- if (emitColumn === 0) {
- this.emitIndent();
- }
- else if (trailing && first && !noLeadingSpace) {
- this.writeToOutput(" ");
- }
-
- if (comment.kind() === SyntaxKind.MultiLineCommentTrivia) {
- this.recordSourceMappingCommentStart(comment);
- this.writeToOutput(text[0]);
-
- if (text.length > 1 || comment.endsLine) {
- for (var i = 1; i < text.length; i++) {
- this.writeLineToOutput("");
- this.emitIndent();
- this.writeToOutput(text[i]);
- }
- this.recordSourceMappingCommentEnd(comment);
- this.writeLineToOutput("");
- // Fall through
- }
- else {
- this.recordSourceMappingCommentEnd(comment);
- this.writeToOutput(" ");
- return;
- }
- }
- else {
- this.recordSourceMappingCommentStart(comment);
- this.writeToOutput(text[0]);
- this.recordSourceMappingCommentEnd(comment);
- this.writeLineToOutput("");
- // Fall through
- }
-
- if (!trailing && emitColumn !== 0) {
- // If we were indented before, stay indented after.
- this.emitIndent();
- }
- }
-
- private text(): ISimpleText {
- return this.document.syntaxTree().text;
- }
-
- public emitComments(ast: ISyntaxElement, pre: boolean, onlyPinnedOrTripleSlashComments: boolean = false) {
- // Emitting the comments for the exprssion inside an arrow function is handled specially
- // in emitFunctionBodyStatements. We don't want to emit those comments a second time.
- if (ast && !isShared(ast) && ast.kind() !== SyntaxKind.Block) {
- if (ast.parent.kind() === SyntaxKind.SimpleArrowFunctionExpression || ast.parent.kind() === SyntaxKind.ParenthesizedArrowFunctionExpression) {
- return;
- }
- }
-
- if (pre) {
- var preComments = TypeScript.ASTHelpers.preComments(ast, this.text());
-
- if (preComments && ast === this.detachedCommentsElement) {
- // We're emitting the comments for the first script element. Skip any
- // copyright comments, as we'll already have emitted those.
- var detachedComments = this.getDetachedComments(ast);
- preComments = preComments.slice(detachedComments.length);
- this.detachedCommentsElement = null;
- }
-
- // We're emitting comments on an elided element. Only keep the comment if it is
- // a triple slash or pinned comment.
- if (preComments && onlyPinnedOrTripleSlashComments) {
- preComments = ArrayUtilities.where(preComments, c => this.isPinnedOrTripleSlash(c));
- }
-
- this.emitCommentsArray(preComments, /*trailing:*/ false);
- }
- else {
- this.emitCommentsArray(ASTHelpers.postComments(ast, this.text()), /*trailing:*/ true);
- }
- }
-
- private isPinnedOrTripleSlash(comment: Comment): boolean {
- var fullText = comment.fullText();
- if (fullText.match(tripleSlashReferenceRegExp)) {
- return true;
- }
- else {
- return fullText.indexOf("/*!") === 0;
- }
- }
-
- private emitCommentsArray(comments: Comment[], trailing: boolean, noLeadingSpace = false): void {
- if (!this.emitOptions.compilationSettings().removeComments() && comments) {
- for (var i = 0, n = comments.length; i < n; i++) {
- this.emitComment(comments[i], trailing, /*first:*/ i === 0, noLeadingSpace);
- }
- }
- }
-
- public emitObjectLiteralExpression(objectLiteral: ObjectLiteralExpressionSyntax) {
- this.recordSourceMappingStart(objectLiteral);
-
- // Try to preserve the newlines between elements that the user had.
- this.writeToken(objectLiteral.openBraceToken);
- this.emitCommaSeparatedList(objectLiteral, objectLiteral.propertyAssignments, /*buffer:*/ " ", /*preserveNewLines:*/ true);
- this.writeToken(objectLiteral.closeBraceToken);
-
- this.recordSourceMappingEnd(objectLiteral);
- }
-
- public emitArrayLiteralExpression(arrayLiteral: ArrayLiteralExpressionSyntax) {
- this.recordSourceMappingStart(arrayLiteral);
-
- // Try to preserve the newlines between elements that the user had.
- this.writeToken(arrayLiteral.openBracketToken);
- this.emitCommaSeparatedList(arrayLiteral, arrayLiteral.expressions, /*buffer:*/ "", /*preserveNewLines:*/ true);
- this.writeToken(arrayLiteral.closeBracketToken);
-
- this.recordSourceMappingEnd(arrayLiteral);
- }
-
- public emitObjectCreationExpression(objectCreationExpression: ObjectCreationExpressionSyntax) {
- this.recordSourceMappingStart(objectCreationExpression);
- this.writeToken(objectCreationExpression.newKeyword);
- this.writeToOutput(" ");
- var target = objectCreationExpression.expression;
-
- this.emit(target);
- if (objectCreationExpression.argumentList) {
- this.recordSourceMappingStart(objectCreationExpression.argumentList);
- this.writeToken(objectCreationExpression.argumentList.openParenToken);
- this.emitCommaSeparatedList(objectCreationExpression.argumentList, objectCreationExpression.argumentList.arguments, /*buffer:*/ "", /*preserveNewLines:*/ false);
- this.writeToken(objectCreationExpression.argumentList.closeParenToken);
- this.recordSourceMappingEnd(objectCreationExpression.argumentList);
- }
-
- this.recordSourceMappingEnd(objectCreationExpression);
- }
-
- public getConstantDecl(dotExpr: MemberAccessExpressionSyntax): PullEnumElementDecl {
- var pullSymbol = this.semanticInfoChain.getSymbolForAST(dotExpr);
- if (pullSymbol && pullSymbol.kind === PullElementKind.EnumMember) {
- var pullDecls = pullSymbol.getDeclarations();
- if (pullDecls.length === 1) {
- var pullDecl = pullDecls[0];
- if (pullDecl.kind === PullElementKind.EnumMember) {
- return pullDecl;
- }
- }
- }
-
- return null;
- }
-
- public tryEmitConstant(dotExpr: MemberAccessExpressionSyntax) {
- var propertyName = dotExpr.name;
- var boundDecl = this.getConstantDecl(dotExpr);
- if (boundDecl) {
- var value = boundDecl.constantValue;
- if (value !== null) {
- this.recordSourceMappingStart(dotExpr);
- this.writeToOutput(value.toString());
- var comment = " /* ";
- comment += propertyName.text();
- comment += " */";
- this.writeToOutput(comment);
- this.recordSourceMappingEnd(dotExpr);
- return true;
- }
- }
-
- return false;
- }
-
- public emitInvocationExpression(callNode: InvocationExpressionSyntax) {
- this.recordSourceMappingStart(callNode);
- var target = callNode.expression;
- var args = callNode.argumentList.arguments;
-
- if (target.kind() === SyntaxKind.MemberAccessExpression && (target).expression.kind() === SyntaxKind.SuperKeyword) {
- this.emit(target);
- this.writeToOutput(".call");
- this.recordSourceMappingStart(args);
- this.writeToken(callNode.argumentList.openParenToken);
- this.emitThis();
- if (args && args.length > 0) {
- this.writeToOutput(", ");
- this.emitCommaSeparatedList(callNode.argumentList, args, /*buffer:*/ "", /*preserveNewLines:*/ false);
- }
- }
- else {
- if (callNode.expression.kind() === SyntaxKind.SuperKeyword && this.emitState.container === EmitContainer.Constructor) {
- this.writeToOutput("_super.call");
- }
- else {
- this.emitJavascript(target, false);
- }
- this.recordSourceMappingStart(args);
- this.writeToken(callNode.argumentList.openParenToken);
- if (callNode.expression.kind() === SyntaxKind.SuperKeyword && this.emitState.container === EmitContainer.Constructor) {
- this.writeToOutput("this");
- if (args && args.length > 0) {
- this.writeToOutput(", ");
- }
- }
- this.emitCommaSeparatedList(callNode.argumentList, args, /*buffer:*/ "", /*preserveNewLines:*/ false);
- }
-
- this.writeToken(callNode.argumentList.closeParenToken);
- this.recordSourceMappingEnd(args);
- this.recordSourceMappingEnd(callNode);
- }
-
- private emitParameterList(list: ParameterListSyntax): void {
- this.writeToken(list.openParenToken);
- this.emitCommentsArray(ASTHelpers.convertTokenTrailingComments(list.openParenToken, this.text()), /*trailing:*/ true, /*noLeadingSpace:*/ true);
- this.emitFunctionParameters(list.parameters, list.parameters);
- this.writeToken(list.closeParenToken);
- }
-
- private emitFunctionParameters(ast: ISyntaxElement, parameters: ParameterSyntax[]): void {
- var argsLen = 0;
-
- if (parameters) {
- this.emitComments(ast, true);
-
- var tempContainer = this.setContainer(EmitContainer.Args);
- argsLen = parameters.length;
- var printLen = argsLen;
- if (lastParameterIsRest(parameters)) {
- printLen--;
- }
- for (var i = 0; i < printLen; i++) {
- var arg = parameters[i];
- this.emit(arg);
-
- if (i < (printLen - 1)) {
- this.writeToOutput(", ");
- if (parameters) {
- this.emitCommentsArray(ASTHelpers.convertTokenTrailingComments(parameters.separatorAt(i), this.text()), /*trailing:*/ true, /*noLeadingSpace:*/ true);
- }
- }
- }
- this.setContainer(tempContainer);
-
- this.emitComments(ast, false);
- }
- }
-
- private emitFunctionBodyStatements(name: string, funcDecl: ISyntaxElement, parameters: ParameterSyntax[], block: BlockSyntax, bodyExpression: ISyntaxElement): void {
- this.writeLineToOutput(" {");
- if (name) {
- this.recordSourceMappingNameStart(name);
- }
-
- this.indenter.increaseIndent();
-
- if (block) {
- // We want any detached statements at the start of hte block to stay at the start.
- // This is important for features like VSDoc which place their comments inside a
- // block, but can't have them preceded by things like "var _this = this" when we
- // emit.
-
- this.emitDetachedComments(block.statements);
- }
-
- // Parameter list parameters with defaults could capture this
- if (this.shouldCaptureThis(funcDecl)) {
- this.writeCaptureThisStatement(funcDecl);
- }
-
- if (parameters) {
- this.emitDefaultValueAssignments(parameters);
- this.emitRestParameterInitializer(parameters);
- }
-
- if (block) {
- this.emitList(block.statements);
- this.emitCommentsArray(ASTHelpers.convertTokenLeadingComments(block.closeBraceToken, this.text()), /*trailing:*/ false);
- }
- else {
- // Copy any comments before the body of the arrow function to the return statement.
- // This is necessary for emitting correctness so we don't emit something like this:
- //
- // return
- // // foo
- // this.foo();
- //
- // Because of ASI, this gets parsed as "return;" which is *not* what we want for
- // proper semantics.
- //var preComments = bodyExpression.preComments();
- //var postComments = bodyExpression.postComments();
-
- //bodyExpression.setPreComments(null);
- //bodyExpression.setPostComments(null);
-
- this.emitIndent();
- this.emitCommentsArray(ASTHelpers.preComments(bodyExpression, this.text()), /*trailing:*/ false);
- this.writeToOutput("return ");
- this.emit(bodyExpression);
- this.writeLineToOutput(";");
- this.emitCommentsArray(ASTHelpers.preComments(bodyExpression, this.text()), /*trailing:*/ true);
-
- //bodyExpression.setPreComments(preComments);
- //bodyExpression.setPostComments(postComments);
- }
-
- this.indenter.decreaseIndent();
- this.emitIndent();
-
- if (block) {
- this.writeToken(block.closeBraceToken);
- }
- else {
- this.writeToOutputWithSourceMapRecord("}", bodyExpression);
- }
-
- if (name) {
- this.recordSourceMappingNameEnd();
- }
- }
-
- private emitDefaultValueAssignments(parameters: ParameterSyntax[]): void {
- var n = parameters.length;
- if (lastParameterIsRest(parameters)) {
- n--;
- }
-
- for (var i = 0; i < n; i++) {
- var arg = parameters[i];
- var id = arg.identifier;
- var equalsValueClause = arg.equalsValueClause;
- if (equalsValueClause) {
- this.emitIndent();
- this.recordSourceMappingStart(arg);
- this.writeToOutput("if (typeof " + id.text() + " === \"undefined\") { ");//
- this.writeToken(id);
- this.emitJavascript(equalsValueClause, false);
- this.writeLineToOutput("; }");
- this.recordSourceMappingEnd(arg);
- }
- }
- }
-
- private emitRestParameterInitializer(parameters: ParameterSyntax[]): void {
- if (lastParameterIsRest(parameters)) {
- var n = parameters.length;
- var lastArg = parameters[n - 1];
- var id = lastArg.identifier;
- this.emitIndent();
- this.recordSourceMappingStart(lastArg);
- this.writeToOutput("var ");
- this.writeToken(id);
- this.writeLineToOutput(" = [];");
- this.recordSourceMappingEnd(lastArg);
- this.emitIndent();
- this.writeToOutput("for (");
- this.writeToOutputWithSourceMapRecord("var _i = 0;", lastArg);
- this.writeToOutput(" ");
- this.writeToOutputWithSourceMapRecord("_i < (arguments.length - " + (n - 1) + ")", lastArg);
- this.writeToOutput("; ");
- this.writeToOutputWithSourceMapRecord("_i++", lastArg);
- this.writeLineToOutput(") {");
- this.indenter.increaseIndent();
- this.emitIndent();
-
- this.writeToOutputWithSourceMapRecord(id.text() + "[_i] = arguments[_i + " + (n - 1) + "];", lastArg);
- this.writeLineToOutput("");
- this.indenter.decreaseIndent();
- this.emitIndent();
- this.writeLineToOutput("}");
- }
- }
-
- private getImportDecls(fileName: string): PullDecl[] {
- var topLevelDecl = this.semanticInfoChain.topLevelDecl(this.document.fileName);
- var result: PullDecl[] = [];
-
- var dynamicModuleDecl = topLevelDecl.getChildDecls()[0]; // Dynamic module declaration has to be present
- var queue: PullDecl[] = dynamicModuleDecl.getChildDecls();
-
- for (var i = 0, n = queue.length; i < n; i++) {
- var decl = queue[i];
-
- if (decl.kind & PullElementKind.TypeAlias) {
- var importStatementAST = this.semanticInfoChain.getASTForDecl(decl);
- if (importStatementAST.moduleReference.kind() === SyntaxKind.ExternalModuleReference) { // external module
- var symbol = decl.getSymbol(this.semanticInfoChain);
- var typeSymbol = symbol && symbol.type;
- if (typeSymbol && typeSymbol !== this.semanticInfoChain.anyTypeSymbol && !typeSymbol.isError()) {
- result.push(decl);
- }
- }
- }
- }
-
- return result;
- }
-
- public getModuleImportAndDependencyList(sourceUnit: SourceUnitSyntax) {
- var importList = "";
- var dependencyList = "";
-
- var importDecls = this.getImportDecls(this.document.fileName);
-
- // all dependencies are quoted
- if (importDecls.length) {
- for (var i = 0; i < importDecls.length; i++) {
- var importStatementDecl = importDecls[i];
- var importStatementSymbol = importStatementDecl.getSymbol(this.semanticInfoChain);
- var importStatementAST = this.semanticInfoChain.getASTForDecl(importStatementDecl);
-
- if (importStatementSymbol.isUsedAsValue()) {
- if (i <= importDecls.length - 1) {
- dependencyList += ", ";
- importList += ", ";
- }
-
- importList += importStatementDecl.name;
- dependencyList += (importStatementAST.moduleReference).stringLiteral.text();
- }
- }
- }
-
- // emit any potential amd dependencies
- var amdDependencies = this.document.syntaxTree().amdDependencies();
- for (var i = 0; i < amdDependencies.length; i++) {
- dependencyList += ", \"" + amdDependencies[i] + "\"";
- }
-
- return {
- importList: importList,
- dependencyList: dependencyList
- };
- }
-
- public shouldCaptureThis(ast: ISyntaxElement) {
- if (ast.kind() === SyntaxKind.SourceUnit) {
- var scriptDecl = this.semanticInfoChain.topLevelDecl(this.document.fileName);
- return hasFlag(scriptDecl.flags, PullElementFlags.MustCaptureThis);
- }
-
- var decl = this.semanticInfoChain.getDeclForAST(ast);
- if (decl) {
- return hasFlag(decl.flags, PullElementFlags.MustCaptureThis);
- }
-
- return false;
- }
-
- public emitEnum(moduleDecl: EnumDeclarationSyntax) {
- var pullDecl = this.semanticInfoChain.getDeclForAST(moduleDecl);
- this.pushDecl(pullDecl);
-
- var svModuleName = this.moduleName;
- this.moduleName = moduleDecl.identifier.text();
-
- var temp = this.setContainer(EmitContainer.Module);
- var isExported = hasFlag(pullDecl.flags, PullElementFlags.Exported);
-
- if (!isExported) {
- this.recordSourceMappingStart(moduleDecl);
- this.writeToOutput("var ");
- this.writeToOutputWithSourceMapRecord(this.moduleName, moduleDecl.identifier);
- this.writeLineToOutput(";");
- this.recordSourceMappingEnd(moduleDecl);
- this.emitIndent();
- }
-
- this.writeToOutput("(");
- this.recordSourceMappingStart(moduleDecl);
- this.writeToOutput("function (");
- this.writeToOutputWithSourceMapRecord(this.moduleName, moduleDecl.identifier);
- this.writeLineToOutput(") {");
-
- this.recordSourceMappingNameStart(this.moduleName);
-
- this.indenter.increaseIndent();
-
- if (this.shouldCaptureThis(moduleDecl)) {
- this.writeCaptureThisStatement(moduleDecl);
- }
-
- this.emitSeparatedList(moduleDecl.enumElements);
- this.indenter.decreaseIndent();
- this.emitIndent();
-
- var parentIsDynamic = temp === EmitContainer.DynamicModule;
- if (temp === EmitContainer.Prog && isExported) {
- this.writeToOutput("}");
- this.recordSourceMappingNameEnd();
- this.writeToOutput(")(this." + this.moduleName + " || (this." + this.moduleName + " = {}));");
- }
- else if (isExported || temp === EmitContainer.Prog) {
- var dotMod = svModuleName !== "" ? (parentIsDynamic ? "exports" : svModuleName) + "." : svModuleName;
- this.writeToOutput("}");
- this.recordSourceMappingNameEnd();
- this.writeToOutput(")(" + dotMod + this.moduleName + " || (" + dotMod + this.moduleName + " = {}));");
- }
- else if (!isExported && temp !== EmitContainer.Prog) {
- this.writeToOutput("}");
- this.recordSourceMappingNameEnd();
- this.writeToOutput(")(" + this.moduleName + " || (" + this.moduleName + " = {}));");
- }
- else {
- this.writeToOutput("}");
- this.recordSourceMappingNameEnd();
- this.writeToOutput(")();");
- }
-
- this.recordSourceMappingEnd(moduleDecl);
- if (temp !== EmitContainer.Prog && isExported) {
- this.recordSourceMappingStart(moduleDecl);
- if (parentIsDynamic) {
- this.writeLineToOutput("");
- this.emitIndent();
- this.writeToOutput("var " + this.moduleName + " = exports." + this.moduleName + ";");
- }
- else {
- this.writeLineToOutput("");
- this.emitIndent();
- this.writeToOutput("var " + this.moduleName + " = " + svModuleName + "." + this.moduleName + ";");
- }
- this.recordSourceMappingEnd(moduleDecl);
- }
-
- this.setContainer(temp);
- this.moduleName = svModuleName;
-
- this.popDecl(pullDecl);
- }
-
- private getModuleDeclToVerifyChildNameCollision(moduleDecl: PullDecl, changeNameIfAnyDeclarationInContext: boolean) {
- if (ArrayUtilities.contains(this.declStack, moduleDecl)) {
- // Given decl is in the scope, we would need to check for child name collision
- return moduleDecl;
- }
- else if (changeNameIfAnyDeclarationInContext) {
- // Check if any other declaration of the given symbol is in scope
- // (eg. when emitting expression of type defined from different declaration in reopened module)
- var symbol = moduleDecl.getSymbol(this.semanticInfoChain);
- if (symbol) {
- var otherDecls = symbol.getDeclarations();
- for (var i = 0; i < otherDecls.length; i++) {
- // If the other decl is in the scope, use this decl to determine which name to display
- if (ArrayUtilities.contains(this.declStack, otherDecls[i])) {
- return otherDecls[i];
- }
- }
- }
- }
-
- return null;
- }
-
- private hasChildNameCollision(moduleName: string, parentDecl: PullDecl) {
- var childDecls = parentDecl.getChildDecls();
- return ArrayUtilities.any(childDecls, (childDecl: PullDecl) => {
- var childAST = this.semanticInfoChain.getASTForDecl(childDecl);
- // Enum member it can never conflict with module name as it is property of the enum
- // Only if this child would be emitted we need to look further in
- if (childDecl.kind != PullElementKind.EnumMember && this.shouldEmit(childAST)) {
- // same name child
- if (childDecl.name === moduleName) {
- // collision if the parent was not class
- if (parentDecl.kind != PullElementKind.Class) {
- return true;
- }
-
- // If the parent was class, we would find name collision if this was not a property/method/accessor
- if (!(childDecl.kind == PullElementKind.Method ||
- childDecl.kind == PullElementKind.Property ||
- childDecl.kind == PullElementKind.SetAccessor ||
- childDecl.kind == PullElementKind.GetAccessor)) {
- return true;
- }
- }
-
- // Check if the name collision exists in any of the children
- if (this.hasChildNameCollision(moduleName, childDecl)) {
- return true;
- }
- }
- return false;
- });
- }
-
- // Get the moduleName to write in js file
- // If changeNameIfAnyDeclarationInContext is true, verify if any of the declarations for the symbol would need rename.
- private getModuleName(moduleDecl: PullDecl, changeNameIfAnyDeclarationInContext?: boolean) {
- var moduleName = moduleDecl.name;
- var moduleDisplayName = moduleDecl.getDisplayName();
-
- // If the decl is in stack it may need name change in the js file
- moduleDecl = this.getModuleDeclToVerifyChildNameCollision(moduleDecl, changeNameIfAnyDeclarationInContext);
- if (moduleDecl && moduleDecl.kind != PullElementKind.Enum) {
- // If there is any child that would be emitted with same name as module, js files would need to use rename for the module
- while (this.hasChildNameCollision(moduleName, moduleDecl)) {
- // there was name collision with member which could result in faulty codegen, try rename with prepend of '_'
- moduleName = "_" + moduleName;
- moduleDisplayName = "_" + moduleDisplayName;
- }
- }
-
- return moduleDisplayName;
- }
-
- private emitModuleDeclarationWorker(moduleDecl: ModuleDeclarationSyntax) {
- if (moduleDecl.stringLiteral) {
- this.emitSingleModuleDeclaration(moduleDecl, moduleDecl.stringLiteral);
- }
- else {
- var moduleNames = ASTHelpers.getModuleNames(moduleDecl.name);
- this.emitSingleModuleDeclaration(moduleDecl, moduleNames[0]);
- }
- }
-
- private writeToken(token: ISyntaxToken) {
- if (token) {
- this.writeToOutputWithSourceMapRecord(token.text(), token);
- }
- }
-
- public emitSingleModuleDeclaration(moduleDecl: ModuleDeclarationSyntax, moduleName: ISyntaxToken) {
- var isLastName = ASTHelpers.isLastNameOfModule(moduleDecl, moduleName);
-
- if (isLastName) {
- // Doc Comments on the ast belong to the innermost module being emitted.
- this.emitComments(moduleDecl, true);
- }
-
- var pullDecl = this.semanticInfoChain.getDeclForAST(moduleName);
- this.pushDecl(pullDecl);
-
- var svModuleName = this.moduleName;
-
- if (moduleDecl.stringLiteral) {
- this.moduleName = tokenValueText(moduleDecl.stringLiteral);
- if (isTSFile(this.moduleName)) {
- this.moduleName = this.moduleName.substring(0, this.moduleName.length - ".ts".length);
- }
- }
- else {
- this.moduleName = moduleName.text();
- }
-
- var temp = this.setContainer(EmitContainer.Module);
- var isExported = hasFlag(pullDecl.flags, PullElementFlags.Exported);
-
- // prologue
-
- if (!isExported) {
- this.recordSourceMappingStart(moduleDecl);
- this.writeToOutput("var ");
- this.writeToOutputWithSourceMapRecord(this.moduleName, moduleName);
- this.writeLineToOutput(";");
- this.recordSourceMappingEnd(moduleDecl);
- this.emitIndent();
- }
-
- this.writeToOutput("(");
- this.recordSourceMappingStart(moduleDecl);
- this.writeToOutput("function (");
- // Use the name that doesnt conflict with its members,
- // this.moduleName needs to be updated to make sure that export member declaration is emitted correctly
- this.moduleName = this.getModuleName(pullDecl);
- this.writeToOutputWithSourceMapRecord(this.moduleName, moduleName);
- this.writeLineToOutput(") {");
-
- this.recordSourceMappingNameStart(moduleName.text());
-
- this.indenter.increaseIndent();
-
- if (this.shouldCaptureThis(moduleDecl)) {
- this.writeCaptureThisStatement(moduleDecl);
- }
-
- if (moduleName === moduleDecl.stringLiteral) {
- this.emitList(moduleDecl.moduleElements);
- }
- else {
- var moduleNames = ASTHelpers.getModuleNames(moduleDecl.name);
- var nameIndex = moduleNames.indexOf(moduleName);
-
- Debug.assert(nameIndex >= 0);
-
- if (isLastName) {
- // If we're on the innermost module, we can emit the module elements.
- this.emitList(moduleDecl.moduleElements);
- }
- else {
- // otherwise, just recurse and emit the next module in the A.B.C module name.
- this.emitIndent();
- this.emitSingleModuleDeclaration(moduleDecl, moduleNames[nameIndex + 1]);
- this.writeLineToOutput("");
- }
- }
-
- this.moduleName = moduleName.text();
- this.indenter.decreaseIndent();
- this.emitIndent();
-
- // epilogue
- var parentIsDynamic = temp === EmitContainer.DynamicModule;
- this.recordSourceMappingStart(moduleDecl.closeBraceToken);
- if (temp === EmitContainer.Prog && isExported) {
- this.writeToOutput("}");
- this.recordSourceMappingNameEnd();
- this.recordSourceMappingEnd(moduleDecl.closeBraceToken);
- this.writeToOutput(")(this." + this.moduleName + " || (this." + this.moduleName + " = {}));");
- }
- else if (isExported || temp === EmitContainer.Prog) {
- var dotMod = svModuleName !== "" ? (parentIsDynamic ? "exports" : svModuleName) + "." : svModuleName;
- this.writeToOutput("}");
- this.recordSourceMappingNameEnd();
- this.recordSourceMappingEnd(moduleDecl.closeBraceToken);
- this.writeToOutput(")(" + dotMod + this.moduleName + " || (" + dotMod + this.moduleName + " = {}));");
- }
- else if (!isExported && temp !== EmitContainer.Prog) {
- this.writeToOutput("}");
- this.recordSourceMappingNameEnd();
- this.recordSourceMappingEnd(moduleDecl.closeBraceToken);
- this.writeToOutput(")(" + this.moduleName + " || (" + this.moduleName + " = {}));");
- }
- else {
- this.writeToOutput("}");
- this.recordSourceMappingNameEnd();
- this.recordSourceMappingEnd(moduleDecl.closeBraceToken);
- this.writeToOutput(")();");
- }
-
- this.recordSourceMappingEnd(moduleDecl);
- if (temp !== EmitContainer.Prog && isExported) {
- this.recordSourceMappingStart(moduleDecl);
- if (parentIsDynamic) {
- this.writeLineToOutput("");
- this.emitIndent();
- this.writeToOutput("var " + this.moduleName + " = exports." + this.moduleName + ";");
- }
- else {
- this.writeLineToOutput("");
- this.emitIndent();
- this.writeToOutput("var " + this.moduleName + " = " + svModuleName + "." + this.moduleName + ";");
- }
- this.recordSourceMappingEnd(moduleDecl);
- }
-
- this.setContainer(temp);
- this.moduleName = svModuleName;
-
- this.popDecl(pullDecl);
-
- if (isLastName) {
- // Comments on the module ast belong to the innermost module being emitted.
- this.emitComments(moduleDecl, false);
- }
- }
-
- public emitEnumElement(varDecl: EnumElementSyntax): void {
- // [[""] = ] = "";
- var pullDecl = this.semanticInfoChain.getDeclForAST(varDecl);
- Debug.assert(pullDecl && pullDecl.kind === PullElementKind.EnumMember);
-
- this.emitComments(varDecl, true);
- this.recordSourceMappingStart(varDecl);
-
- var representation = (varDecl.propertyName.kind() === SyntaxKind.StringLiteral)
- ? varDecl.propertyName.text()
- : ('"' + tokenValueText(varDecl.propertyName) + '"');
-
- this.writeToOutput(this.moduleName);
- this.writeToOutput('[');
- this.writeToOutput(this.moduleName);
- this.writeToOutput('[');
- this.writeToOutput(representation);
- this.writeToOutput(']');
-
- if (varDecl.equalsValueClause) {
- this.emit(varDecl.equalsValueClause);
- }
- else if (pullDecl.constantValue !== null) {
- this.writeToOutput(' = ');
- this.writeToOutput(pullDecl.constantValue.toString());
- }
- else {
- this.writeToOutput(' = null');
- }
-
- this.writeToOutput('] = ');
- this.writeToOutput(representation);
- this.recordSourceMappingEnd(varDecl);
- this.emitComments(varDecl, false);
- this.writeToOutput(';');
- }
-
- public emitElementAccessExpression(expression: ElementAccessExpressionSyntax) {
- this.recordSourceMappingStart(expression);
- this.emit(expression.expression);
- this.writeToken(expression.openBracketToken);
- this.emit(expression.argumentExpression);
- this.writeToken(expression.closeBracketToken);
- this.recordSourceMappingEnd(expression);
- }
-
- public emitSimpleArrowFunctionExpression(arrowFunction: SimpleArrowFunctionExpressionSyntax): void {
- this.emitAnyArrowFunctionExpression(arrowFunction, arrowFunction.block, arrowFunction.expression);
- }
-
- public emitParenthesizedArrowFunctionExpression(arrowFunction: ParenthesizedArrowFunctionExpressionSyntax): void {
- this.emitAnyArrowFunctionExpression(arrowFunction, arrowFunction.block, arrowFunction.expression);
- }
-
- private emitAnyArrowFunctionExpression(arrowFunction: ISyntaxElement, block: BlockSyntax, expression: ISyntaxElement): void {
- var savedInArrowFunction = this.inArrowFunction;
- this.inArrowFunction = true;
-
- var temp = this.setContainer(EmitContainer.Function);
-
- this.recordSourceMappingStart(arrowFunction);
-
- // Start
- var pullDecl = this.semanticInfoChain.getDeclForAST(arrowFunction);
- this.pushDecl(pullDecl);
-
- this.emitComments(arrowFunction, true);
-
- this.recordSourceMappingStart(arrowFunction);
- this.writeToOutput("function ");
-
- var parameters: ParameterSyntax[] = null;
- if (arrowFunction.kind() === SyntaxKind.ParenthesizedArrowFunctionExpression) {
- var parenthesizedArrowFunction = arrowFunction;
-
- parameters = parenthesizedArrowFunction.callSignature.parameterList.parameters;
- this.emitParameterList(parenthesizedArrowFunction.callSignature.parameterList);
- }
- else {
- var parameter = (arrowFunction).parameter;
- parameters = [parameter];
- this.writeToOutput("(");
- this.emitFunctionParameters(parameter, parameters);
- this.writeToOutput(")");
- }
-
- this.emitFunctionBodyStatements(/*funcName:*/ null, arrowFunction, parameters, block, expression);
-
- this.recordSourceMappingEnd(arrowFunction);
-
- // The extra call is to make sure the caller's funcDecl end is recorded, since caller wont be able to record it
- this.recordSourceMappingEnd(arrowFunction);
-
- this.emitComments(arrowFunction, false);
-
- this.popDecl(pullDecl);
- this.setContainer(temp);
- this.inArrowFunction = savedInArrowFunction;
- }
-
- public emitConstructor(funcDecl: ConstructorDeclarationSyntax) {
- if (!funcDecl.block) {
- return;
- }
- var temp = this.setContainer(EmitContainer.Constructor);
-
- this.recordSourceMappingStart(funcDecl);
-
- var pullDecl = this.semanticInfoChain.getDeclForAST(funcDecl);
- this.pushDecl(pullDecl);
-
- this.emitComments(funcDecl, true);
-
- this.recordSourceMappingStart(funcDecl);
- this.writeToOutput("function ");
- this.writeToOutput(this.thisClassNode.identifier.text());
-
- this.emitParameterList(funcDecl.callSignature.parameterList);
- this.writeLineToOutput(" {");
-
- this.recordSourceMappingNameStart("constructor");
- this.indenter.increaseIndent();
-
- var parameters = funcDecl.callSignature.parameterList.parameters;
- this.emitDefaultValueAssignments(parameters);
- this.emitRestParameterInitializer(parameters);
-
- if (this.shouldCaptureThis(funcDecl)) {
- this.writeCaptureThisStatement(funcDecl);
- }
-
- this.emitConstructorStatements(funcDecl);
- this.emitCommentsArray(ASTHelpers.convertTokenLeadingComments(funcDecl.block.closeBraceToken, this.text()), /*trailing:*/ false);
-
- this.indenter.decreaseIndent();
- this.emitIndent();
- this.writeToken(funcDecl.block.closeBraceToken);
-
- this.recordSourceMappingNameEnd();
- this.recordSourceMappingEnd(funcDecl);
-
- // The extra call is to make sure the caller's funcDecl end is recorded, since caller wont be able to record it
- this.recordSourceMappingEnd(funcDecl);
-
- this.emitComments(funcDecl, false);
-
- this.popDecl(pullDecl);
- this.setContainer(temp);
- }
-
- public emitGetAccessor(accessor: GetAccessorSyntax): void {
- this.recordSourceMappingStart(accessor);
- this.writeToOutput("get ");
-
- var temp = this.setContainer(EmitContainer.Function);
-
- this.recordSourceMappingStart(accessor);
-
- var pullDecl = this.semanticInfoChain.getDeclForAST(accessor);
- this.pushDecl(pullDecl);
-
- this.recordSourceMappingStart(accessor);
-
- var accessorSymbol = PullHelpers.getAccessorSymbol(accessor, this.semanticInfoChain);
- var container = accessorSymbol.getContainer();
- var containerKind = container.kind;
-
- this.recordSourceMappingNameStart(accessor.propertyName.text());
- this.writeToOutput(accessor.propertyName.text());
- this.emitParameterList(accessor.callSignature.parameterList);
-
- this.emitFunctionBodyStatements(null, accessor, accessor.callSignature.parameterList.parameters, accessor.block, /*bodyExpression:*/ null);
-
- this.recordSourceMappingEnd(accessor);
-
- // The extra call is to make sure the caller's funcDecl end is recorded, since caller wont be able to record it
- this.recordSourceMappingEnd(accessor);
-
- this.popDecl(pullDecl);
- this.setContainer(temp);
- this.recordSourceMappingEnd(accessor);
- }
-
- public emitSetAccessor(accessor: SetAccessorSyntax): void {
- this.recordSourceMappingStart(accessor);
- this.writeToOutput("set ");
-
- var temp = this.setContainer(EmitContainer.Function);
-
- this.recordSourceMappingStart(accessor);
-
- var pullDecl = this.semanticInfoChain.getDeclForAST(accessor);
- this.pushDecl(pullDecl);
-
- this.recordSourceMappingStart(accessor);
-
- var accessorSymbol = PullHelpers.getAccessorSymbol(accessor, this.semanticInfoChain);
- var container = accessorSymbol.getContainer();
- var containerKind = container.kind;
-
- this.recordSourceMappingNameStart(accessor.propertyName.text());
- this.writeToOutput(accessor.propertyName.text());
-
- this.emitParameterList(accessor.callSignature.parameterList);
-
- this.emitFunctionBodyStatements(null, accessor, accessor.callSignature.parameterList.parameters, accessor.block, /*bodyExpression:*/ null);
-
- this.recordSourceMappingEnd(accessor);
-
- // The extra call is to make sure the caller's funcDecl end is recorded, since caller wont be able to record it
- this.recordSourceMappingEnd(accessor);
-
- this.popDecl(pullDecl);
- this.setContainer(temp);
- this.recordSourceMappingEnd(accessor);
- }
-
- public emitFunctionExpression(funcDecl: FunctionExpressionSyntax): void {
- var savedInArrowFunction = this.inArrowFunction;
- this.inArrowFunction = false;
-
- var temp = this.setContainer(EmitContainer.Function);
-
- var funcName = funcDecl.identifier ? funcDecl.identifier.text() : null;//.getNameText();
-
- this.recordSourceMappingStart(funcDecl);
-
- var pullDecl = this.semanticInfoChain.getDeclForAST(funcDecl);
- this.pushDecl(pullDecl);
-
- this.recordSourceMappingStart(funcDecl);
- this.writeToken(funcDecl.functionKeyword);
- this.writeToOutput(" ");
-
- //var id = funcDecl.getNameText();
- if (funcDecl.identifier) {
- this.writeToOutputWithSourceMapRecord(funcDecl.identifier.text(), funcDecl.identifier);
- }
-
- this.emitParameterList(funcDecl.callSignature.parameterList);
- this.emitFunctionBodyStatements(funcName, funcDecl, funcDecl.callSignature.parameterList.parameters, funcDecl.block, /*bodyExpression:*/ null);
-
- this.recordSourceMappingEnd(funcDecl);
-
- // The extra call is to make sure the caller's funcDecl end is recorded, since caller wont be able to record it
- this.recordSourceMappingEnd(funcDecl);
-
- this.emitComments(funcDecl, false);
-
- this.popDecl(pullDecl);
-
- this.setContainer(temp);
- this.inArrowFunction = savedInArrowFunction;
- }
-
- public emitFunction(funcDecl: FunctionDeclarationSyntax) {
- if (funcDecl.block === null) {
- return;
- }
- var savedInArrowFunction = this.inArrowFunction;
- this.inArrowFunction = false;
-
- var temp = this.setContainer(EmitContainer.Function);
-
- var funcName = funcDecl.identifier.text();
-
- this.recordSourceMappingStart(funcDecl);
-
- var printName = funcDecl.identifier !== null
- var pullDecl = this.semanticInfoChain.getDeclForAST(funcDecl);
- this.pushDecl(pullDecl);
-
- this.emitComments(funcDecl, true);
-
- this.recordSourceMappingStart(funcDecl);
- this.writeToken(funcDecl.functionKeyword);
- this.writeToOutput(" ");
-
- if (printName) {
- var id = funcDecl.identifier.text();
- if (id) {
- if (funcDecl.identifier) {
- this.recordSourceMappingStart(funcDecl.identifier);
- }
- this.writeToOutput(id);
- if (funcDecl.identifier) {
- this.recordSourceMappingEnd(funcDecl.identifier);
- }
- }
- }
-
- this.emitParameterList(funcDecl.callSignature.parameterList);
-
- var parameters = funcDecl.callSignature.parameterList.parameters;
- this.emitFunctionBodyStatements(funcDecl.identifier.text(), funcDecl, parameters, funcDecl.block, /*bodyExpression:*/ null);
-
- this.recordSourceMappingEnd(funcDecl);
-
- // The extra call is to make sure the caller's funcDecl end is recorded, since caller wont be able to record it
- this.recordSourceMappingEnd(funcDecl);
-
- this.emitComments(funcDecl, false);
-
- this.popDecl(pullDecl);
-
- this.setContainer(temp);
- this.inArrowFunction = savedInArrowFunction;
-
- if (funcDecl.block) {
- var pullFunctionDecl = this.semanticInfoChain.getDeclForAST(funcDecl);
- if ((this.emitState.container === EmitContainer.Module || this.emitState.container === EmitContainer.DynamicModule) && pullFunctionDecl && hasFlag(pullFunctionDecl.flags, PullElementFlags.Exported)) {
- this.writeLineToOutput("");
- this.emitIndent();
- var modName = this.emitState.container === EmitContainer.Module ? this.moduleName : "exports";
- this.recordSourceMappingStart(funcDecl);
- this.writeToOutput(modName + "." + funcName + " = " + funcName + ";");
- this.recordSourceMappingEnd(funcDecl);
- }
- }
- }
-
- public emitAmbientVarDecl(varDecl: VariableDeclaratorSyntax) {
- this.recordSourceMappingStart(this.currentVariableDeclaration);
- if (varDecl.equalsValueClause) {
- this.emitComments(varDecl, true);
- this.recordSourceMappingStart(varDecl);
- this.writeToOutputWithSourceMapRecord(varDecl.propertyName.text(), varDecl.propertyName);
- this.emitJavascript(varDecl.equalsValueClause, false);
- this.recordSourceMappingEnd(varDecl);
- this.emitComments(varDecl, false);
- }
- }
-
- // Emits "var " if it is allowed
- public emitVarDeclVar() {
- if (this.currentVariableDeclaration) {
- this.writeToOutput("var ");
- }
- }
-
- public emitVariableDeclaration(declaration: VariableDeclarationSyntax) {
- var varDecl = declaration.variableDeclarators[0];
-
- var symbol = this.semanticInfoChain.getSymbolForAST(varDecl);
-
- var parentSymbol = symbol ? symbol.getContainer() : null;
- var parentKind = parentSymbol ? parentSymbol.kind : PullElementKind.None;
-
- this.emitComments(declaration, true);
-
- var pullVarDecl = this.semanticInfoChain.getDeclForAST(varDecl);
- var isAmbientWithoutInit = pullVarDecl && hasFlag(pullVarDecl.flags, PullElementFlags.Ambient) && varDecl.equalsValueClause === null;
- if (!isAmbientWithoutInit) {
- var prevVariableDeclaration = this.currentVariableDeclaration;
- this.currentVariableDeclaration = declaration;
-
- for (var i = 0, n = declaration.variableDeclarators.length; i < n; i++) {
- var declarator = declaration.variableDeclarators[i];
-
- if (i > 0) {
- this.writeToOutput(", ");
- }
-
- this.emit(declarator);
- }
- this.currentVariableDeclaration = prevVariableDeclaration;
-
- // Declarator emit would take care of emitting start of the variable declaration start
- this.recordSourceMappingEnd(declaration);
- }
-
- this.emitComments(declaration, false);
- }
-
- private emitMemberVariableDeclaration(varDecl: MemberVariableDeclarationSyntax) {
- Debug.assert(!hasModifier(varDecl.modifiers, PullElementFlags.Static) && varDecl.variableDeclarator.equalsValueClause);
-
- var pullDecl = this.semanticInfoChain.getDeclForAST(varDecl);
- this.pushDecl(pullDecl);
-
- this.emitComments(varDecl, true);
- this.recordSourceMappingStart(varDecl);
-
- var varDeclName = varDecl.variableDeclarator.propertyName.text();
- var quotedOrNumber = isQuoted(varDeclName) || varDecl.variableDeclarator.propertyName.kind() !== SyntaxKind.IdentifierName;
-
- var symbol = this.semanticInfoChain.getSymbolForAST(varDecl);
- var parentSymbol = symbol ? symbol.getContainer() : null;
- var parentDecl = pullDecl && pullDecl.getParentDecl();
-
- if (quotedOrNumber) {
- this.writeToOutput("this[");
- }
- else {
- this.writeToOutput("this.");
- }
-
- this.writeToOutputWithSourceMapRecord(varDecl.variableDeclarator.propertyName.text(), varDecl.variableDeclarator.propertyName);
-
- if (quotedOrNumber) {
- this.writeToOutput("]");
- }
-
- if (varDecl.variableDeclarator.equalsValueClause) {
- // Ensure we have a fresh var list count when recursing into the variable
- // initializer. We don't want our current list of variables to affect how we
- // emit nested variable lists.
- var prevVariableDeclaration = this.currentVariableDeclaration;
- this.emit(varDecl.variableDeclarator.equalsValueClause);
- this.currentVariableDeclaration = prevVariableDeclaration;
- }
-
- // class
- if (this.emitState.container !== EmitContainer.Args) {
- this.writeToOutput(";");
- }
-
- this.recordSourceMappingEnd(varDecl);
- this.emitComments(varDecl, false);
-
- this.popDecl(pullDecl);
- }
-
- public emitVariableDeclarator(varDecl: VariableDeclaratorSyntax) {
- var pullDecl = this.semanticInfoChain.getDeclForAST(varDecl);
- this.pushDecl(pullDecl);
- if (pullDecl && (pullDecl.flags & PullElementFlags.Ambient) === PullElementFlags.Ambient) {
- this.emitAmbientVarDecl(varDecl);
- }
- else {
- this.emitComments(varDecl, true);
- this.recordSourceMappingStart(this.currentVariableDeclaration);
- this.recordSourceMappingStart(varDecl);
-
- var varDeclName = varDecl.propertyName.text();
-
- var symbol = this.semanticInfoChain.getSymbolForAST(varDecl);
- var parentSymbol = symbol ? symbol.getContainer() : null;
- var parentDecl = pullDecl && pullDecl.getParentDecl();
- var parentIsModule = parentDecl && (parentDecl.flags & PullElementFlags.SomeInitializedModule);
-
- if (parentIsModule) {
- // module
- if (!hasFlag(pullDecl.flags, PullElementFlags.Exported)/* && !varDecl.isProperty() */) {
- this.emitVarDeclVar();
- }
- else {
- if (this.emitState.container === EmitContainer.DynamicModule) {
- this.writeToOutput("exports.");
- }
- else {
- this.writeToOutput(this.moduleName + ".");
- }
- }
- }
- else {
- this.emitVarDeclVar();
- }
-
- this.writeToOutputWithSourceMapRecord(varDecl.propertyName.text(), varDecl.propertyName);
-
- if (varDecl.equalsValueClause) {
- // Ensure we have a fresh var list count when recursing into the variable
- // initializer. We don't want our current list of variables to affect how we
- // emit nested variable lists.
- var prevVariableDeclaration = this.currentVariableDeclaration;
- this.emit(varDecl.equalsValueClause);
- this.currentVariableDeclaration = prevVariableDeclaration;
- }
-
- this.recordSourceMappingEnd(varDecl);
- this.emitComments(varDecl, false);
- }
- this.currentVariableDeclaration = undefined;
- this.popDecl(pullDecl);
- }
-
- private symbolIsUsedInItsEnclosingContainer(symbol: PullSymbol, dynamic = false) {
- var symDecls = symbol.getDeclarations();
-
- if (symDecls.length) {
- var enclosingDecl = this.getEnclosingDecl();
- if (enclosingDecl) {
- var parentDecl = symDecls[0].getParentDecl();
- if (parentDecl) {
- var symbolDeclarationEnclosingContainer = parentDecl;
- var enclosingContainer = enclosingDecl;
-
- // compute the closing container of the symbol's declaration
- while (symbolDeclarationEnclosingContainer) {
- if (symbolDeclarationEnclosingContainer.kind === (dynamic ? PullElementKind.DynamicModule : PullElementKind.Container)) {
- break;
- }
- symbolDeclarationEnclosingContainer = symbolDeclarationEnclosingContainer.getParentDecl();
- }
-
- // if the symbol in question is not a global, compute the nearest
- // enclosing declaration from the point of usage
- if (symbolDeclarationEnclosingContainer) {
- while (enclosingContainer) {
- if (enclosingContainer.kind === (dynamic ? PullElementKind.DynamicModule : PullElementKind.Container)) {
- break;
- }
-
- enclosingContainer = enclosingContainer.getParentDecl();
- }
- }
-
- if (symbolDeclarationEnclosingContainer && enclosingContainer) {
- var same = symbolDeclarationEnclosingContainer === enclosingContainer;
-
- // initialized module object variables are bound to their parent's decls
- if (!same && symbol.anyDeclHasFlag(PullElementFlags.InitializedModule)) {
- same = symbolDeclarationEnclosingContainer === enclosingContainer.getParentDecl();
- }
-
- return same;
- }
- }
- }
- }
-
- return false;
- }
-
- // In some cases, when emitting a name, the emitter needs to qualify a symbol
- // name by first emitting its parent's name. This generally happens when the
- // name referenced is in scope in TypeScript, but not in Javascript. This is true
- // in any of the following 3 cases:
- // - It is an enum member, even if accessed from within the enum declaration in which it is defined
- // - It is an exported var, even if accessed from within the module declaration in which it is defined
- // - It is an exported member of the current module, but is never defined in this particular module
- // declaration (i.e. it is only defined in other components of the same merged module)
- private shouldQualifySymbolNameWithParentName(symbol: PullSymbol): boolean {
- var enclosingContextDeclPath = this.declStack;
- var symbolDeclarations = symbol.getDeclarations();
- for (var i = 0; i < symbolDeclarations.length; i++) {
- var currentDecl = symbolDeclarations[i];
- var declParent = currentDecl.getParentDecl();
-
- if (currentDecl.kind === PullElementKind.EnumMember) {
- return true;
- }
-
- // All decls of the same symbol must agree on whether they are exported
- // If one decl is not exported, none of them are, and it is safe to
- // assume it is just a local
- if (!hasFlag(currentDecl.flags, PullElementFlags.Exported)) {
- return false;
- }
-
- // Section 10.6:
- // When a variable is exported, all references to the variable in the body of the
- // module are replaced with
- // .< VariableName>
- if (currentDecl.kind === PullElementKind.Variable && !hasFlag(currentDecl.flags, PullElementFlags.ImplicitVariable)) {
- return true;
- }
-
- if (ArrayUtilities.contains(this.declStack, declParent)) {
- return false;
- }
- }
-
- return true;
- }
-
- // Get the symbol information to be used for emitting the ast
- private getSymbolForEmit(ast: ISyntaxElement) {
- var pullSymbol = this.semanticInfoChain.getSymbolForAST(ast);
- var pullSymbolAlias = this.semanticInfoChain.getAliasSymbolForAST(ast);
- if (pullSymbol && pullSymbolAlias) {
- var symbolToCompare = isTypesOnlyLocation(ast) ?
- pullSymbolAlias.getExportAssignedTypeSymbol() :
- pullSymbolAlias.getExportAssignedValueSymbol();
-
- if (pullSymbol === symbolToCompare) {
- pullSymbol = pullSymbolAlias;
- pullSymbolAlias = null;
- }
- }
- return { symbol: pullSymbol, aliasSymbol: pullSymbolAlias };
- }
-
- public emitName(name: ISyntaxToken, addThis: boolean) {
- this.emitComments(name, true);
- this.recordSourceMappingStart(name);
- if (name.text().length > 0) {
- var symbolForEmit = this.getSymbolForEmit(name);
- var pullSymbol = symbolForEmit.symbol;
- if (!pullSymbol) {
- pullSymbol = this.semanticInfoChain.anyTypeSymbol;
- }
- var pullSymbolAlias = symbolForEmit.aliasSymbol;
- var pullSymbolKind = pullSymbol.kind;
- var isLocalAlias = pullSymbolAlias && (pullSymbolAlias.getDeclarations()[0].getParentDecl() === this.getEnclosingDecl());
- if (addThis && (this.emitState.container !== EmitContainer.Args) && pullSymbol) {
- var pullSymbolContainer = pullSymbol.getContainer();
-
- if (pullSymbolContainer) {
- var pullSymbolContainerKind = pullSymbolContainer.kind;
-
- if (PullHelpers.symbolIsModule(pullSymbolContainer) || pullSymbolContainerKind === PullElementKind.Enum ||
- pullSymbolContainer.anyDeclHasFlag(PullElementFlags.InitializedModule | PullElementFlags.Enum)) {
- var needToEmitParentName = this.shouldQualifySymbolNameWithParentName(pullSymbol);
- if (needToEmitParentName) {
- var parentDecl = pullSymbol.getDeclarations()[0].getParentDecl();
- Debug.assert(parentDecl && !parentDecl.isRootDecl());
- this.writeToOutput(this.getModuleName(parentDecl, /* changeNameIfAnyDeclarationInContext */ true) + ".");
- }
- }
- else if (pullSymbolContainerKind === PullElementKind.DynamicModule ||
- pullSymbolContainer.anyDeclHasFlag(PullElementFlags.InitializedDynamicModule)) {
- if (pullSymbolKind === PullElementKind.Property) {
- // If dynamic module
- this.writeToOutput("exports.");
- }
- else if (pullSymbol.anyDeclHasFlag(PullElementFlags.Exported) &&
- !isLocalAlias &&
- !pullSymbol.anyDeclHasFlag(PullElementFlags.ImplicitVariable) &&
- pullSymbol.kind !== PullElementKind.ConstructorMethod &&
- pullSymbol.kind !== PullElementKind.Class &&
- pullSymbol.kind !== PullElementKind.Enum) {
- this.writeToOutput("exports.");
- }
- }
- }
- }
-
- this.writeToOutput(name.text());
- }
-
- this.recordSourceMappingEnd(name);
- this.emitComments(name, false);
- }
-
- public recordSourceMappingNameStart(name: string) {
- if (this.sourceMapper) {
- var nameIndex = -1;
- if (name) {
- if (this.sourceMapper.currentNameIndex.length > 0) {
- var parentNameIndex = this.sourceMapper.currentNameIndex[this.sourceMapper.currentNameIndex.length - 1];
- if (parentNameIndex !== -1) {
- name = this.sourceMapper.names[parentNameIndex] + "." + name;
- }
- }
-
- // Look if there already exists name
- var nameIndex = this.sourceMapper.names.length - 1;
- for (nameIndex; nameIndex >= 0; nameIndex--) {
- if (this.sourceMapper.names[nameIndex] === name) {
- break;
- }
- }
-
- if (nameIndex === -1) {
- nameIndex = this.sourceMapper.names.length;
- this.sourceMapper.names.push(name);
- }
- }
- this.sourceMapper.currentNameIndex.push(nameIndex);
- }
- }
-
- public recordSourceMappingNameEnd() {
- if (this.sourceMapper) {
- this.sourceMapper.currentNameIndex.pop();
- }
- }
-
- private recordSourceMappingStart(ast: ISyntaxElement) {
- if (this.sourceMapper && ASTHelpers.isValidAstNode(ast)) {
- var text = this.text();
- this.recordSourceMappingSpanStart(ast, start(ast, text), end(ast, text));
- }
- }
-
- private recordSourceMappingCommentStart(comment: Comment) {
- this.recordSourceMappingSpanStart(comment, comment.start(), comment.end());
- }
-
- private recordSourceMappingSpanStart(ast: any, start: number, end: number) {
- if (this.sourceMapper && ast && start !== -1 && end !== -1) {
- var lineCol = { line: -1, character: -1 };
- var sourceMapping = new SourceMapping();
- sourceMapping.start.emittedColumn = this.emitState.column;
- sourceMapping.start.emittedLine = this.emitState.line;
- // REVIEW: check time consumed by this binary search (about two per leaf statement)
- var lineMap = this.document.lineMap();
- lineMap.fillLineAndCharacterFromPosition(start, lineCol);
- sourceMapping.start.sourceColumn = lineCol.character;
- sourceMapping.start.sourceLine = lineCol.line + 1;
- lineMap.fillLineAndCharacterFromPosition(end, lineCol);
- sourceMapping.end.sourceColumn = lineCol.character;
- sourceMapping.end.sourceLine = lineCol.line + 1;
-
- Debug.assert(!isNaN(sourceMapping.start.emittedColumn));
- Debug.assert(!isNaN(sourceMapping.start.emittedLine));
- Debug.assert(!isNaN(sourceMapping.start.sourceColumn));
- Debug.assert(!isNaN(sourceMapping.start.sourceLine));
- Debug.assert(!isNaN(sourceMapping.end.sourceColumn));
- Debug.assert(!isNaN(sourceMapping.end.sourceLine));
-
- if (this.sourceMapper.currentNameIndex.length > 0) {
- sourceMapping.nameIndex = this.sourceMapper.currentNameIndex[this.sourceMapper.currentNameIndex.length - 1];
- }
- // Set parent and child relationship
- var siblings = this.sourceMapper.currentMappings[this.sourceMapper.currentMappings.length - 1];
- siblings.push(sourceMapping);
- this.sourceMapper.currentMappings.push(sourceMapping.childMappings);
- this.sourceMapper.increaseMappingLevel(ast);
- }
- }
-
- private recordSourceMappingEnd(ast: ISyntaxElement) {
- if (this.sourceMapper && ASTHelpers.isValidAstNode(ast)) {
- var text = this.text();
- this.recordSourceMappingSpanEnd(ast, start(ast, text), end(ast, text));
- }
- }
-
- private recordSourceMappingCommentEnd(ast: Comment) {
- if (this.sourceMapper && ASTHelpers.isValidSpan(ast)) {
- this.recordSourceMappingSpanEnd(ast, ast.start(), ast.end());
- }
- }
-
- private recordSourceMappingSpanEnd(ast: any, start: number, end: number) {
- if (this.sourceMapper && ast && start !== -1 && end !== -1) {
- // Pop source mapping childs
- this.sourceMapper.currentMappings.pop();
-
- // Get the last source mapping from sibling list = which is the one we are recording end for
- var siblings = this.sourceMapper.currentMappings[this.sourceMapper.currentMappings.length - 1];
- var sourceMapping = siblings[siblings.length - 1];
-
- sourceMapping.end.emittedColumn = this.emitState.column;
- sourceMapping.end.emittedLine = this.emitState.line;
-
- Debug.assert(!isNaN(sourceMapping.end.emittedColumn));
- Debug.assert(!isNaN(sourceMapping.end.emittedLine));
-
- this.sourceMapper.decreaseMappingLevel(ast);
- }
- }
-
- // Note: may throw exception.
- public getOutputFiles(): OutputFile[] {
- // Output a source mapping. As long as we haven't gotten any errors yet.
- var result: OutputFile[] = [];
- if (this.sourceMapper !== null) {
- this.sourceMapper.emitSourceMapping();
- result.push(this.sourceMapper.getOutputFile());
- }
-
- result.push(this.outfile.getOutputFile());
- return result;
- }
-
- private emitParameterPropertyAndMemberVariableAssignments(): void {
- // emit any parameter properties first
- var constructorDecl = getLastConstructor(this.thisClassNode);
-
- if (constructorDecl) {
- for (var i = 0, n = constructorDecl.callSignature.parameterList.parameters.length; i < n; i++) {
- var parameter = constructorDecl.callSignature.parameterList.parameters[i];
-
- var parameterDecl = this.semanticInfoChain.getDeclForAST(parameter);
- if (hasFlag(parameterDecl.flags, PullElementFlags.PropertyParameter)) {
- this.emitIndent();
- this.recordSourceMappingStart(parameter);
- this.writeToOutputWithSourceMapRecord("this." + parameter.identifier.text(), parameter.identifier);
- this.writeToOutput(" = ");
- this.writeToOutputWithSourceMapRecord(parameter.identifier.text(), parameter.identifier);
- this.writeLineToOutput(";");
- this.recordSourceMappingEnd(parameter);
- }
- }
- }
-
- for (var i = 0, n = this.thisClassNode.classElements.length; i < n; i++) {
- if (this.thisClassNode.classElements[i].kind() === SyntaxKind.MemberVariableDeclaration) {
- var varDecl = this.thisClassNode.classElements[i];
- if (!hasModifier(varDecl.modifiers, PullElementFlags.Static) && varDecl.variableDeclarator.equalsValueClause) {
- this.emitIndent();
- this.emitMemberVariableDeclaration(varDecl);
- this.writeLineToOutput("");
- }
- }
- }
- }
-
- private isOnSameLine(pos1: number, pos2: number): boolean {
- if (pos1 < 0 || pos2 < 0) {
- // Missing element. Assume it's on the same line as the other element.
- return true;
- }
-
- var lineMap = this.document.lineMap();
- return lineMap.getLineNumberFromPosition(pos1) === lineMap.getLineNumberFromPosition(pos2);
- }
-
- private emitCommaSeparatedList(parent: ISyntaxElement, list: T[], buffer: string, preserveNewLines: boolean): void {
- if (list === null || list.length === 0) {
- return;
- }
-
- // If the first element isn't on hte same line as the parent node, then we need to
- // start with a newline.
- var text = this.text();
- var startLine = preserveNewLines && !this.isOnSameLine(end(parent, text), end(list[0], text));
-
- if (preserveNewLines) {
- // Any elements on a new line will have to be indented.
- this.indenter.increaseIndent();
- }
-
- // If we're starting on a newline, then emit an actual newline. Otherwise write out
- // the buffer character before hte first element.
- if (startLine) {
- this.writeLineToOutput("");
- }
- else {
- this.writeToOutput(buffer);
- }
-
- for (var i = 0, n = list.length; i < n; i++) {
- var emitNode = list[i];
-
- // Write out the element, emitting an indent if we're on a new line.
- this.emitJavascript(emitNode, startLine);
-
- if (i < (n - 1)) {
- // If the next element start on a different line than this element ended on,
- // then we want to start on a newline. Emit the comma with a newline.
- // Otherwise, emit the comma with the space.
- startLine = preserveNewLines && !this.isOnSameLine(end(emitNode, text), start(list[i + 1], text));
- if (startLine) {
- this.writeLineToOutput(",");
- }
- else {
- this.writeToOutput(", ");
- }
- }
- }
-
- if (preserveNewLines) {
- // We're done with all the elements. Return the indent back to where it was.
- this.indenter.decreaseIndent();
- }
-
- // If the last element isn't on the same line as the parent, then emit a newline
- // after the last element and emit our indent so the list's terminator will be
- // on the right line. Otherwise, emit the buffer string between the last value
- // and the terminator.
- if (preserveNewLines && !this.isOnSameLine(end(parent, text), end(list[list.length - 1], text))) {
- this.writeLineToOutput("");
- this.emitIndent();
- }
- else {
- this.writeToOutput(buffer);
- }
- }
-
- public emitList(list: T[], useNewLineSeparator = true, startInclusive = 0, endExclusive = list.length) {
- if (list === null) {
- return;
- }
-
- this.emitComments(list, true);
- var lastEmittedNode: ISyntaxElement = null;
-
- for (var i = startInclusive; i < endExclusive; i++) {
- var node = list[i];
-
- if (this.shouldEmit(node)) {
- this.emitSpaceBetweenConstructs(lastEmittedNode, node);
-
- this.emitJavascript(node, true);
- if (useNewLineSeparator) {
- this.writeLineToOutput("");
- }
-
- lastEmittedNode = node;
- }
- }
-
- this.emitComments(list, false);
- }
-
- public emitSeparatedList(list: T[], useNewLineSeparator = true, startInclusive = 0, endExclusive = list.length) {
- if (list === null) {
- return;
- }
-
- this.emitComments(list, true);
- var lastEmittedNode: ISyntaxElement = null;
-
- for (var i = startInclusive; i < endExclusive; i++) {
- var node = list[i];
-
- if (this.shouldEmit(node)) {
- this.emitSpaceBetweenConstructs(lastEmittedNode, node);
-
- this.emitJavascript(node, true);
- if (useNewLineSeparator) {
- this.writeLineToOutput("");
- }
-
- lastEmittedNode = node;
- }
- }
-
- this.emitComments(list, false);
- }
-
- private isDirectivePrologueElement(node: ISyntaxElement) {
- if (node.kind() === SyntaxKind.ExpressionStatement) {
- var exprStatement = node;
- return exprStatement.expression.kind() === SyntaxKind.StringLiteral;
- }
-
- return false;
- }
-
- // If these two constructs had more than one line between them originally, then emit at
- // least one blank line between them.
- public emitSpaceBetweenConstructs(node1: ISyntaxElement, node2: ISyntaxElement): void {
- if (node1 === null || node2 === null) {
- return;
- }
-
- var text = this.text();
- if (start(node1, text) === -1 || end(node1, text) === -1 || start(node2, text) === -1 || end(node2, text) === -1) {
- return;
- }
-
- var lineMap = this.document.lineMap();
- var node1EndLine = lineMap.getLineNumberFromPosition(end(node1, text));
- var node2StartLine = lineMap.getLineNumberFromPosition(start(node2, text));
-
- if ((node2StartLine - node1EndLine) > 1) {
- this.writeLineToOutput("", /*force:*/ true);
- }
- }
-
- // We consider a sequence of comments to be a detached from an ast if there are no blank lines
- // between them, and there is a blank line after the last one and the node they're attached
- // to.
- private getDetachedComments(element: ISyntaxElement): Comment[] {
- var text = this.text();
- var preComments = TypeScript.ASTHelpers.preComments(element, text);
- if (preComments) {
- var lineMap = this.document.lineMap();
-
- var detachedComments: Comment[] = [];
- var lastComment: Comment = null;
-
- for (var i = 0, n = preComments.length; i < n; i++) {
- var comment = preComments[i];
-
- if (lastComment) {
- var lastCommentLine = lineMap.getLineNumberFromPosition(lastComment.end());
- var commentLine = lineMap.getLineNumberFromPosition(comment.start());
-
- if (commentLine >= lastCommentLine + 2) {
- // There was a blank line between the last comment and this comment. This
- // comment is not part of the copyright comments. Return what we have so
- // far.
- return detachedComments;
- }
- }
-
- detachedComments.push(comment);
- lastComment = comment;
- }
-
- // All comments look like they could have been part of the copyright header. Make
- // sure there is at least one blank line between it and the node. If not, it's not
- // a copyright header.
- var lastCommentLine = lineMap.getLineNumberFromPosition(ArrayUtilities.last(detachedComments).end());
- var astLine = lineMap.getLineNumberFromPosition(start(element, text));
- if (astLine >= lastCommentLine + 2) {
- return detachedComments;
- }
- }
-
- // No usable copyright comments found.
- return [];
- }
-
- private emitPossibleCopyrightHeaders(script: SourceUnitSyntax): void {
- this.emitDetachedComments(script.moduleElements);
- }
-
- private emitDetachedComments(list: ISyntaxNodeOrToken[]): void {
- if (list.length > 0) {
- var firstElement = childAt(list, 0);
-
- this.detachedCommentsElement = firstElement;
- this.emitCommentsArray(this.getDetachedComments(this.detachedCommentsElement), /*trailing:*/ false);
- }
- }
-
- public emitScriptElements(sourceUnit: SourceUnitSyntax) {
- var list = sourceUnit.moduleElements;
-
- this.emitPossibleCopyrightHeaders(sourceUnit);
-
- // First, emit all the prologue elements.
- for (var i = 0, n = list.length; i < n; i++) {
- var node = list[i];
-
- if (!this.isDirectivePrologueElement(node)) {
- break;
- }
-
- this.emitJavascript(node, true);
- this.writeLineToOutput("");
- }
-
- // Now emit __extends or a _this capture if necessary.
- this.emitPrologue(sourceUnit);
-
- var isExternalModule = this.document.syntaxTree().isExternalModule();
- var isNonElidedExternalModule = isExternalModule && !ASTHelpers.scriptIsElided(sourceUnit);
- if (isNonElidedExternalModule) {
- this.recordSourceMappingStart(sourceUnit);
-
- if (this.emitOptions.compilationSettings().moduleGenTarget() === ModuleGenTarget.Asynchronous) { // AMD
- var dependencyList = "[\"require\", \"exports\"";
- var importList = "require, exports";
-
- var importAndDependencyList = this.getModuleImportAndDependencyList(sourceUnit);
- importList += importAndDependencyList.importList;
- dependencyList += importAndDependencyList.dependencyList + "]";
-
- this.writeLineToOutput("define(" + dependencyList + "," + " function(" + importList + ") {");
- }
- }
-
- if (isExternalModule) {
- var temp = this.setContainer(EmitContainer.DynamicModule);
-
- var svModuleName = this.moduleName;
- this.moduleName = syntaxTree(sourceUnit).fileName();
- if (TypeScript.isTSFile(this.moduleName)) {
- this.moduleName = this.moduleName.substring(0, this.moduleName.length - ".ts".length);
- }
-
- // if the external module has an "export =" identifier, we'll
- // set it in the ExportAssignment emit method
- this.setExportAssignment(null);
-
- if(this.emitOptions.compilationSettings().moduleGenTarget() === ModuleGenTarget.Asynchronous) {
- this.indenter.increaseIndent();
- }
-
- var externalModule = this.semanticInfoChain.getDeclForAST(this.document.sourceUnit());
-
- if (hasFlag(externalModule.flags, PullElementFlags.MustCaptureThis)) {
- this.writeCaptureThisStatement(sourceUnit);
- }
-
- this.pushDecl(externalModule);
- }
-
- this.emitList(list, /*useNewLineSeparator:*/ true, /*startInclusive:*/ i, /*endExclusive:*/ n);
-
- if (isExternalModule) {
- if (this.emitOptions.compilationSettings().moduleGenTarget() === ModuleGenTarget.Asynchronous) {
- this.indenter.decreaseIndent();
- }
-
- if (isNonElidedExternalModule) {
- var exportAssignment = this.getExportAssignment();
- var exportAssignmentIdentifierText = exportAssignment ? exportAssignment.identifier.text() : null;
- var exportAssignmentValueSymbol = (externalModule.getSymbol(this.semanticInfoChain)).getExportAssignedValueSymbol();
-
- if (this.emitOptions.compilationSettings().moduleGenTarget() === ModuleGenTarget.Asynchronous) { // AMD
- if (exportAssignmentIdentifierText && exportAssignmentValueSymbol && !(exportAssignmentValueSymbol.kind & PullElementKind.SomeTypeReference)) {
- // indent was decreased for AMD above
- this.indenter.increaseIndent();
- this.emitIndent();
- this.writeToOutputWithSourceMapRecord("return " + exportAssignmentIdentifierText, exportAssignment);
- this.writeLineToOutput(";");
- this.indenter.decreaseIndent();
- }
- this.writeToOutput("});");
- }
- else if (exportAssignmentIdentifierText && exportAssignmentValueSymbol && !(exportAssignmentValueSymbol.kind & PullElementKind.SomeTypeReference)) {
- this.emitIndent();
- this.writeToOutputWithSourceMapRecord("module.exports = " + exportAssignmentIdentifierText, exportAssignment);
- this.writeToOutput(";");
- }
-
- this.recordSourceMappingEnd(sourceUnit);
- this.writeLineToOutput("");
- }
-
- this.setContainer(temp);
- this.moduleName = svModuleName;
- this.popDecl(externalModule);
- }
- }
-
- public emitConstructorStatements(funcDecl: ConstructorDeclarationSyntax) {
- var list = funcDecl.block.statements;
-
- if (list === null) {
- return;
- }
-
- this.emitComments(list, true);
-
- var emitPropertyAssignmentsAfterSuperCall = ASTHelpers.getExtendsHeritageClause(this.thisClassNode.heritageClauses) !== null;
- var propertyAssignmentIndex = emitPropertyAssignmentsAfterSuperCall ? 1 : 0;
- var lastEmittedNode: ISyntaxElement = null;
-
- for (var i = 0, n = list.length; i < n; i++) {
- // In some circumstances, class property initializers must be emitted immediately after the 'super' constructor
- // call which, in these cases, must be the first statement in the constructor body
- if (i === propertyAssignmentIndex) {
- this.emitParameterPropertyAndMemberVariableAssignments();
- }
-
- var node = list[i];
-
- if (this.shouldEmit(node)) {
- this.emitSpaceBetweenConstructs(lastEmittedNode, node);
-
- this.emitJavascript(node, true);
- this.writeLineToOutput("");
-
- lastEmittedNode = node;
- }
- }
-
- if (i === propertyAssignmentIndex) {
- this.emitParameterPropertyAndMemberVariableAssignments();
- }
-
- this.emitComments(list, false);
- }
-
- // tokenId is the id the preceding token
- public emitJavascript(ast: ISyntaxElement, startLine: boolean) {
- if (ast === null) {
- return;
- }
-
- if (startLine &&
- this.indenter.indentAmt > 0) {
-
- this.emitIndent();
- }
-
- this.emit(ast);
- }
-
- public emitAccessorMemberDeclaration(funcDecl: ISyntaxElement, name: ISyntaxToken, className: string, isProto: boolean) {
- if (funcDecl.kind() !== SyntaxKind.GetAccessor) {
- var accessorSymbol = PullHelpers.getAccessorSymbol(funcDecl, this.semanticInfoChain);
- if (accessorSymbol.getGetter()) {
- return;
- }
- }
-
- this.emitIndent();
- this.recordSourceMappingStart(funcDecl);
-
- this.writeToOutput("Object.defineProperty(" + className);
- if (isProto) {
- this.writeToOutput(".prototype, ");
- }
- else {
- this.writeToOutput(", ");
- }
-
- var functionName = name.text();
- if (isQuoted(functionName)) {
- this.writeToOutput(functionName);
- }
- else {
- this.writeToOutput('"' + functionName + '"');
- }
-
- this.writeLineToOutput(", {");
-
- this.indenter.increaseIndent();
-
- var accessors = PullHelpers.getGetterAndSetterFunction(funcDecl, this.semanticInfoChain);
- if (accessors.getter) {
- this.emitIndent();
- this.recordSourceMappingStart(accessors.getter);
- this.emitComments(accessors.getter, true);
- this.writeToOutput("get: ");
- this.emitAccessorBody(accessors.getter, accessors.getter.callSignature.parameterList, accessors.getter.block);
- this.writeLineToOutput(",");
- }
-
- if (accessors.setter) {
- this.emitIndent();
- this.recordSourceMappingStart(accessors.setter);
- this.emitComments(accessors.setter, true);
- this.writeToOutput("set: ");
- this.emitAccessorBody(accessors.setter, accessors.setter.callSignature.parameterList, accessors.setter.block);
- this.writeLineToOutput(",");
- }
-
- this.emitIndent();
- this.writeLineToOutput("enumerable: true,");
- this.emitIndent();
- this.writeLineToOutput("configurable: true");
- this.indenter.decreaseIndent();
- this.emitIndent();
- this.writeLineToOutput("});");
- this.recordSourceMappingEnd(funcDecl);
- }
-
- private emitAccessorBody(funcDecl: ISyntaxElement, parameterList: ParameterListSyntax, block: BlockSyntax): void {
- var pullDecl = this.semanticInfoChain.getDeclForAST(funcDecl);
- this.pushDecl(pullDecl);
-
- this.recordSourceMappingStart(funcDecl);
- this.writeToOutput("function ");
- this.emitParameterList(parameterList);
-
- var parameters = parameterList.parameters;
- this.emitFunctionBodyStatements(null, funcDecl, parameters, block, /*bodyExpression:*/ null);
-
- this.recordSourceMappingEnd(funcDecl);
-
- // The extra call is to make sure the caller's funcDecl end is recorded, since caller wont be able to record it
- this.recordSourceMappingEnd(funcDecl);
- this.popDecl(pullDecl);
- }
-
- public emitClass(classDecl: ClassDeclarationSyntax) {
- var pullDecl = this.semanticInfoChain.getDeclForAST(classDecl);
- this.pushDecl(pullDecl);
-
- var svClassNode = this.thisClassNode;
- this.thisClassNode = classDecl;
- var className = classDecl.identifier.text();
- this.emitComments(classDecl, true);
- var temp = this.setContainer(EmitContainer.Class);
-
- this.recordSourceMappingStart(classDecl);
- this.writeToOutput("var " + className);
-
- var hasBaseClass = ASTHelpers.getExtendsHeritageClause(classDecl.heritageClauses) !== null;
- var baseTypeReference: ISyntaxElement = null;
- var varDecl: VariableDeclaratorSyntax = null;
-
- if (hasBaseClass) {
- this.writeLineToOutput(" = (function (_super) {");
- }
- else {
- this.writeLineToOutput(" = (function () {");
- }
-
- this.recordSourceMappingNameStart(className);
- this.indenter.increaseIndent();
-
- if (hasBaseClass) {
- baseTypeReference = ASTHelpers.getExtendsHeritageClause(classDecl.heritageClauses).typeNames[0];
- this.emitIndent();
- this.writeToOutputWithSourceMapRecord("__extends(" + className + ", _super)", baseTypeReference);
- this.writeLineToOutput(";");
- }
-
- this.emitIndent();
-
- var constrDecl = getLastConstructor(classDecl);
-
- // output constructor
- if (constrDecl) {
- // declared constructor
- this.emit(constrDecl);
- this.writeLineToOutput("");
- }
- else {
- this.recordSourceMappingStart(classDecl);
- // default constructor
- this.indenter.increaseIndent();
- this.writeLineToOutput("function " + classDecl.identifier.text() + "() {");
- this.recordSourceMappingNameStart("constructor");
- if (hasBaseClass) {
- this.emitIndent();
- this.writeToOutputWithSourceMapRecord("_super.apply(this, arguments)", baseTypeReference);
- this.writeLineToOutput(";");
- }
-
- if (this.shouldCaptureThis(classDecl)) {
- this.writeCaptureThisStatement(classDecl);
- }
-
- this.emitParameterPropertyAndMemberVariableAssignments();
-
- this.indenter.decreaseIndent();
- this.emitIndent();
- this.writeToken(classDecl.closeBraceToken);
- this.writeLineToOutput("");
-
- this.recordSourceMappingNameEnd();
- this.recordSourceMappingEnd(classDecl);
- }
-
- this.emitClassMembers(classDecl);
-
- this.emitIndent();
- this.writeToOutputWithSourceMapRecord("return " + className + ";", classDecl.closeBraceToken);
- this.writeLineToOutput("");
- this.indenter.decreaseIndent();
- this.emitIndent();
- this.writeToken(classDecl.closeBraceToken);
- this.recordSourceMappingNameEnd();
- this.recordSourceMappingStart(classDecl);
- this.writeToOutput(")(");
- if (hasBaseClass) {
- this.emitJavascript(baseTypeReference, /*startLine:*/ false);
- }
- this.writeToOutput(");");
- this.recordSourceMappingEnd(classDecl);
-
- if ((temp === EmitContainer.Module || temp === EmitContainer.DynamicModule) && hasFlag(pullDecl.flags, PullElementFlags.Exported)) {
- this.writeLineToOutput("");
- this.emitIndent();
- var modName = temp === EmitContainer.Module ? this.moduleName : "exports";
- this.writeToOutputWithSourceMapRecord(modName + "." + className + " = " + className + ";", classDecl);
- }
-
- this.recordSourceMappingEnd(classDecl);
- this.emitComments(classDecl, false);
- this.setContainer(temp);
- this.thisClassNode = svClassNode;
-
- this.popDecl(pullDecl);
- }
-
- private emitClassMembers(classDecl: ClassDeclarationSyntax): void {
- // First, emit all the functions.
- var lastEmittedMember: ISyntaxElement = null;
-
- for (var i = 0, n = classDecl.classElements.length; i < n; i++) {
- var memberDecl = classDecl.classElements[i];
-
- if (memberDecl.kind() === SyntaxKind.GetAccessor) {
- this.emitSpaceBetweenConstructs(lastEmittedMember, memberDecl);
- var getter = memberDecl;
- this.emitAccessorMemberDeclaration(getter, getter.propertyName, classDecl.identifier.text(),
- !hasModifier(getter.modifiers, PullElementFlags.Static));
- lastEmittedMember = memberDecl;
- }
- else if (memberDecl.kind() === SyntaxKind.SetAccessor) {
- this.emitSpaceBetweenConstructs(lastEmittedMember, memberDecl);
- var setter = memberDecl;
- this.emitAccessorMemberDeclaration(setter, setter.propertyName, classDecl.identifier.text(),
- !hasModifier(setter.modifiers, PullElementFlags.Static));
- lastEmittedMember = memberDecl;
- }
- else if (memberDecl.kind() === SyntaxKind.MemberFunctionDeclaration) {
-
- var memberFunction = memberDecl;
-
- if (memberFunction.block) {
- this.emitSpaceBetweenConstructs(lastEmittedMember, memberDecl);
-
- this.emitClassMemberFunctionDeclaration(classDecl, memberFunction);
- lastEmittedMember = memberDecl;
- }
- }
- }
-
- // Now emit all the statics.
- for (var i = 0, n = classDecl.classElements.length; i < n; i++) {
- var memberDecl = classDecl.classElements[i];
-
- if (memberDecl.kind() === SyntaxKind.MemberVariableDeclaration) {
- var varDecl = memberDecl;
-
- if (hasModifier(varDecl.modifiers, PullElementFlags.Static) && varDecl.variableDeclarator.equalsValueClause) {
- this.emitSpaceBetweenConstructs(lastEmittedMember, varDecl);
-
- this.emitIndent();
- this.recordSourceMappingStart(varDecl);
-
- this.emitComments(varDecl, true);
- var varDeclName = varDecl.variableDeclarator.propertyName.text();
- if (isQuoted(varDeclName) || varDecl.variableDeclarator.propertyName.kind() !== SyntaxKind.IdentifierName) {
- this.writeToOutput(classDecl.identifier.text() + "[" + varDeclName + "]");
- }
- else {
- this.writeToOutput(classDecl.identifier.text() + "." + varDeclName);
- }
-
- this.emit(varDecl.variableDeclarator.equalsValueClause);
-
- this.recordSourceMappingEnd(varDecl);
- this.writeLineToOutput(";");
-
- lastEmittedMember = varDecl;
- }
- }
- }
- }
-
- private emitClassMemberFunctionDeclaration(classDecl: ClassDeclarationSyntax, funcDecl: MemberFunctionDeclarationSyntax): void {
- this.emitIndent();
- this.recordSourceMappingStart(funcDecl);
- this.emitComments(funcDecl, true);
- var functionName = funcDecl.propertyName.text();
-
- this.writeToOutput(classDecl.identifier.text());
-
- if (!hasModifier(funcDecl.modifiers, PullElementFlags.Static)) {
- this.writeToOutput(".prototype");
- }
-
- if (isQuoted(functionName) || funcDecl.propertyName.kind() !== SyntaxKind.IdentifierName) {
- this.writeToOutput("[" + functionName + "] = ");
- }
- else {
- this.writeToOutput("." + functionName + " = ");
- }
-
- var pullDecl = this.semanticInfoChain.getDeclForAST(funcDecl);
- this.pushDecl(pullDecl);
-
- this.recordSourceMappingStart(funcDecl);
- this.writeToOutput("function ");
-
- this.emitParameterList(funcDecl.callSignature.parameterList);
-
- var parameters = funcDecl.callSignature.parameterList.parameters;
- this.emitFunctionBodyStatements(funcDecl.propertyName.text(), funcDecl, parameters, funcDecl.block, /*bodyExpression:*/ null);
-
- this.recordSourceMappingEnd(funcDecl);
-
- this.emitComments(funcDecl, false);
-
- this.recordSourceMappingEnd(funcDecl);
- this.popDecl(pullDecl);
-
- this.writeLineToOutput(";");
- }
-
- private requiresExtendsBlock(moduleElements: IModuleElementSyntax[]): boolean {
- for (var i = 0, n = moduleElements.length; i < n; i++) {
- var moduleElement = moduleElements[i];
-
- if (moduleElement.kind() === SyntaxKind.ModuleDeclaration) {
- var moduleAST = moduleElement;
-
- if (!hasModifier(moduleAST.modifiers, PullElementFlags.Ambient) && this.requiresExtendsBlock(moduleAST.moduleElements)) {
- return true;
- }
- }
- else if (moduleElement.kind() === SyntaxKind.ClassDeclaration) {
- var classDeclaration = moduleElement;
-
- if (!hasModifier(classDeclaration.modifiers, PullElementFlags.Ambient) && ASTHelpers.getExtendsHeritageClause(classDeclaration.heritageClauses) !== null) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- public emitPrologue(sourceUnit: SourceUnitSyntax) {
- if (!this.extendsPrologueEmitted) {
- if (this.requiresExtendsBlock(sourceUnit.moduleElements)) {
- this.extendsPrologueEmitted = true;
- this.writeLineToOutput("var __extends = this.__extends || function (d, b) {");
- this.writeLineToOutput(" for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];");
- this.writeLineToOutput(" function __() { this.constructor = d; }");
- this.writeLineToOutput(" __.prototype = b.prototype;");
- this.writeLineToOutput(" d.prototype = new __();");
- this.writeLineToOutput("};");
- }
- }
-
- if (!this.globalThisCapturePrologueEmitted) {
- if (this.shouldCaptureThis(sourceUnit)) {
- this.globalThisCapturePrologueEmitted = true;
- this.writeLineToOutput(this.captureThisStmtString);
- }
- }
- }
-
- public emitThis() {
- if (!this.inWithBlock && this.inArrowFunction) {
- this.writeToOutput("_this");
- }
- else {
- this.writeToOutput("this");
- }
- }
-
- public emitBlockOrStatement(node: ISyntaxElement): void {
- if (node.kind() === SyntaxKind.Block) {
- this.emit(node);
- }
- else {
- this.writeLineToOutput("");
- this.indenter.increaseIndent();
- this.emitJavascript(node, true);
- this.indenter.decreaseIndent();
- }
- }
-
- public emitLiteralExpression(expression: ISyntaxToken): void {
- switch (expression.kind()) {
- case SyntaxKind.NullKeyword:
- this.writeToken(expression);
- break;
- case SyntaxKind.FalseKeyword:
- this.writeToken(expression);
- break;
- case SyntaxKind.TrueKeyword:
- this.writeToken(expression);
- break;
- default:
- throw Errors.abstract();
- }
- }
-
- public emitThisExpression(expression: ISyntaxToken): void {
- if (!this.inWithBlock && this.inArrowFunction) {
- this.writeToOutputWithSourceMapRecord("_this", expression);
- }
- else {
- this.writeToken(expression);
- }
- }
-
- public emitSuperExpression(expression: ISyntaxToken): void {
- if (PullHelpers.isInStaticMemberContext(expression, this.semanticInfoChain)) {
- this.writeToOutputWithSourceMapRecord("_super", expression);
- }
- else {
- this.writeToOutputWithSourceMapRecord("_super.prototype", expression);
- }
- }
-
- private hasTrailingComment(token: ISyntaxToken) {
- return token.hasTrailingTrivia() && token.trailingTrivia().hasComment();
- }
-
- public emitParenthesizedExpression(parenthesizedExpression: ParenthesizedExpressionSyntax): void {
- var omitParentheses = false;
-
- if (parenthesizedExpression.expression.kind() === SyntaxKind.CastExpression && !this.hasTrailingComment(parenthesizedExpression.openParenToken)) {
- var castedExpression = (parenthesizedExpression.expression).expression;
-
- // Make sure we consider all nested cast expressions, e.g.:
- // (-A).x;
- while (castedExpression.kind() == SyntaxKind.CastExpression) {
- castedExpression = (castedExpression).expression;
- }
-
- // We have an expression of the form: (SubExpr)
- // Emitting this as (SubExpr) is really not desirable. Just emit the subexpr as is.
- // We cannot generalize this rule however, as omitting the parentheses could cause change in the semantics of the generated
- // code if the casted expression has a lower precedence than the rest of the expression, e.g.:
- // (new A).foo should be emitted as (new A).foo and not new A.foo
- // (typeof A).toString() should be emitted as (typeof A).toString() and not typeof A.toString()
- // (function foo() { })() should be emitted as an IIF (function foo(){})() and not declaration function foo(){} ()
- // Parenthesis can be safelly removed from:
- // Literals
- // MemberAccessExpressions
- // ElementAccessExpressions
- // InvocationExpression, only if they are not part of an object creation (new) expression; e.g.:
- // new (A()) removing the parentheses would result in calling A as a constructor, instead of calling the
- // result of the function invocation A() as a constructor
- switch (castedExpression.kind()) {
- case SyntaxKind.ParenthesizedExpression:
- case SyntaxKind.IdentifierName:
- case SyntaxKind.NullKeyword:
- case SyntaxKind.ThisKeyword:
- case SyntaxKind.StringLiteral:
- case SyntaxKind.NumericLiteral:
- case SyntaxKind.RegularExpressionLiteral:
- case SyntaxKind.TrueKeyword:
- case SyntaxKind.FalseKeyword:
- case SyntaxKind.ArrayLiteralExpression:
- case SyntaxKind.ObjectLiteralExpression:
- case SyntaxKind.MemberAccessExpression:
- case SyntaxKind.ElementAccessExpression:
- omitParentheses = true;
- break;
-
- case SyntaxKind.InvocationExpression:
- if (parenthesizedExpression.parent.kind() !== SyntaxKind.ObjectCreationExpression) {
- omitParentheses = true;
- }
-
- break;
- }
- }
-
- if (omitParentheses) {
- this.emit(parenthesizedExpression.expression);
- }
- else {
- this.recordSourceMappingStart(parenthesizedExpression);
- this.writeToken(parenthesizedExpression.openParenToken);
- this.emitCommentsArray(ASTHelpers.convertTokenTrailingComments(parenthesizedExpression.openParenToken, this.text()), /*trailing:*/ false);
- this.emit(parenthesizedExpression.expression);
- this.writeToken(parenthesizedExpression.closeParenToken);
- this.recordSourceMappingEnd(parenthesizedExpression);
- }
- }
-
- public emitCastExpression(expression: CastExpressionSyntax): void {
- this.emit(expression.expression);
- }
-
- public emitPrefixUnaryExpression(expression: PrefixUnaryExpressionSyntax): void {
- var nodeType = expression.kind();
-
- this.recordSourceMappingStart(expression);
- switch (nodeType) {
- case SyntaxKind.LogicalNotExpression:
- this.writeToken(expression.operatorToken);
- this.emit(expression.operand);
- break;
- case SyntaxKind.BitwiseNotExpression:
- this.writeToken(expression.operatorToken);
- this.emit(expression.operand);
- break;
- case SyntaxKind.NegateExpression:
- this.writeToken(expression.operatorToken);
- if (expression.operand.kind() === SyntaxKind.NegateExpression || expression.operand.kind() === SyntaxKind.PreDecrementExpression) {
- this.writeToOutput(" ");
- }
- this.emit(expression.operand);
- break;
- case SyntaxKind.PlusExpression:
- this.writeToken(expression.operatorToken);
- if (expression.operand.kind() === SyntaxKind.PlusExpression || expression.operand.kind() === SyntaxKind.PreIncrementExpression) {
- this.writeToOutput(" ");
- }
- this.emit(expression.operand);
- break;
- case SyntaxKind.PreIncrementExpression:
- this.writeToOutputWithSourceMapRecord("++", expression.operatorToken);
- this.emit(expression.operand);
- break;
- case SyntaxKind.PreDecrementExpression:
- this.writeToOutputWithSourceMapRecord("--", expression.operatorToken);
- this.emit(expression.operand);
- break;
- default:
- throw Errors.abstract();
- }
-
- this.recordSourceMappingEnd(expression);
- }
-
- public emitPostfixUnaryExpression(expression: PostfixUnaryExpressionSyntax): void {
- var nodeType = expression.kind();
-
- this.recordSourceMappingStart(expression);
- switch (nodeType) {
- case SyntaxKind.PostIncrementExpression:
- this.emit(expression.operand);
- this.writeToOutputWithSourceMapRecord("++", expression.operatorToken);
- break;
- case SyntaxKind.PostDecrementExpression:
- this.emit(expression.operand);
- this.writeToOutputWithSourceMapRecord("--", expression.operatorToken);
- break;
- default:
- throw Errors.abstract();
- }
-
- this.recordSourceMappingEnd(expression);
- }
-
- public emitTypeOfExpression(expression: TypeOfExpressionSyntax): void {
- this.recordSourceMappingStart(expression);
- this.writeToken(expression.typeOfKeyword);
- this.writeToOutput(" ");
- this.emit(expression.expression);
- this.recordSourceMappingEnd(expression);
- }
-
- public emitDeleteExpression(expression: DeleteExpressionSyntax): void {
- this.recordSourceMappingStart(expression);
- this.writeToken(expression.deleteKeyword);
- this.writeToOutput(" ");
- this.emit(expression.expression);
- this.recordSourceMappingEnd(expression);
- }
-
- public emitVoidExpression(expression: VoidExpressionSyntax): void {
- this.recordSourceMappingStart(expression);
- this.writeToken(expression.voidKeyword);
- this.writeToOutput(" ");
- this.emit(expression.expression);
- this.recordSourceMappingEnd(expression);
- }
-
- private canEmitDottedNameMemberAccessExpression(expression: MemberAccessExpressionSyntax) {
- var memberExpressionNodeType = expression.expression.kind();
-
- // If the memberAccess is of Name or another member access, we could potentially emit the symbol using the this memberAccessSymol
- if (memberExpressionNodeType === SyntaxKind.IdentifierName || memberExpressionNodeType == SyntaxKind.MemberAccessExpression) {
- var memberAccessSymbol = this.getSymbolForEmit(expression).symbol;
- var memberAccessExpressionSymbol = this.getSymbolForEmit(expression.expression).symbol;
- if (memberAccessSymbol && memberAccessExpressionSymbol // We have symbols resolved for this expression and access
- && !this.semanticInfoChain.getAliasSymbolForAST(expression.expression) // The access is not off alias
- && (PullHelpers.symbolIsModule(memberAccessExpressionSymbol) || memberAccessExpressionSymbol.kind === PullElementKind.Enum ||
- memberAccessExpressionSymbol.anyDeclHasFlag(PullElementFlags.InitializedModule | PullElementFlags.Enum))) { // container is module
-
- // If the memberAccess is in the context of the container, we could use the symbol to emit this expression
- var memberAccessSymbolKind = memberAccessSymbol.kind;
- if (memberAccessSymbolKind === PullElementKind.Property
- || memberAccessSymbolKind === PullElementKind.EnumMember
- || (memberAccessSymbol.anyDeclHasFlag(PullElementFlags.Exported) && memberAccessSymbolKind === PullElementKind.Variable && !memberAccessSymbol.anyDeclHasFlag(PullElementFlags.InitializedModule | PullElementFlags.Enum))
- || ((memberAccessSymbol.anyDeclHasFlag(PullElementFlags.Exported) && !this.symbolIsUsedInItsEnclosingContainer(memberAccessSymbol)))) {
-
- // If the expression is member access, we need to verify it as well
- if (memberExpressionNodeType === SyntaxKind.MemberAccessExpression) {
- return this.canEmitDottedNameMemberAccessExpression(expression.expression);
- }
-
- return true;
- }
- }
- }
-
- return false;
- }
-
- // Emit the member access expression using the declPath
- private emitDottedNameMemberAccessExpression(expression: MemberAccessExpressionSyntax) {
- this.recordSourceMappingStart(expression);
- if (expression.expression.kind() === SyntaxKind.MemberAccessExpression) {
- // Emit the dotted name access expression
- this.emitDottedNameMemberAccessExpressionRecurse(expression.expression);
- }
- else { // Name
- this.emitName(expression.expression, /*addThis*/ true);
- }
-
- this.writeToken(expression.dotToken);
- this.emitName(expression.name, /*addThis*/ false);
-
- this.recordSourceMappingEnd(expression);
- }
-
- // Set the right indices for the recursive member access expression before emitting it using the decl path
- private emitDottedNameMemberAccessExpressionRecurse(expression: MemberAccessExpressionSyntax) {
- this.emitComments(expression, true);
- this.emitDottedNameMemberAccessExpression(expression);
- this.emitComments(expression, false);
- }
-
- public emitMemberAccessExpression(expression: MemberAccessExpressionSyntax): void {
- if (!this.tryEmitConstant(expression)) {
- // If the expression is dotted name of the modules, emit it using decl path so the name could be resolved correctly.
- if (this.canEmitDottedNameMemberAccessExpression(expression)) {
- this.emitDottedNameMemberAccessExpression(expression);
- }
- else {
- this.recordSourceMappingStart(expression);
- this.emit(expression.expression);
- this.writeToken(expression.dotToken);
- this.emitName(expression.name, false);
- this.recordSourceMappingEnd(expression);
- }
- }
- }
-
- public emitQualifiedName(name: QualifiedNameSyntax): void {
- this.recordSourceMappingStart(name);
-
- this.emit(name.left);
- this.writeToken(name.dotToken);
- this.emitName(name.right, false);
-
- this.recordSourceMappingEnd(name);
- }
-
- public emitBinaryExpression(expression: BinaryExpressionSyntax): void {
- this.recordSourceMappingStart(expression);
- switch (expression.kind()) {
- case SyntaxKind.CommaExpression:
- this.emit(expression.left);
- this.writeToken(expression.operatorToken);
- this.writeToOutput(" ");
- this.emit(expression.right);
- break;
- default:
- {
- this.emit(expression.left);
- var binOp = SyntaxFacts.getText(SyntaxFacts.getOperatorTokenFromBinaryExpression(expression.kind()));
- this.writeToOutput(" ");
- this.writeToOutputWithSourceMapRecord(binOp, expression.operatorToken);
- this.writeToOutput(" ");
- this.emit(expression.right);
- }
- }
- this.recordSourceMappingEnd(expression);
- }
-
- public emitSimplePropertyAssignment(property: SimplePropertyAssignmentSyntax): void {
- this.recordSourceMappingStart(property);
- this.emit(property.propertyName);
-
- this.writeToken(property.colonToken);
- this.writeToOutput(" ");
- this.emitCommentsArray(ASTHelpers.convertTokenTrailingComments(property.colonToken, this.text()), /*trailing:*/ true, /*noLeadingSpace:*/ true);
-
- this.emit(property.expression);
- this.recordSourceMappingEnd(property);
- }
-
- public emitFunctionPropertyAssignment(funcProp: FunctionPropertyAssignmentSyntax): void {
- this.recordSourceMappingStart(funcProp);
-
- this.emit(funcProp.propertyName);
- this.writeToOutput(": ");
-
- var pullFunctionDecl = this.semanticInfoChain.getDeclForAST(funcProp);
-
- var savedInArrowFunction = this.inArrowFunction;
- this.inArrowFunction = false;
-
- var temp = this.setContainer(EmitContainer.Function);
- var funcName = funcProp.propertyName;
-
- var pullDecl = this.semanticInfoChain.getDeclForAST(funcProp);
- this.pushDecl(pullDecl);
-
- this.recordSourceMappingStart(funcProp);
- this.writeToOutput("function ");
-
- //this.recordSourceMappingStart(funcProp.propertyName);
- //this.writeToOutput(funcProp.propertyName.actualText);
- //this.recordSourceMappingEnd(funcProp.propertyName);
-
- this.emitParameterList(funcProp.callSignature.parameterList);
-
- this.emitFunctionBodyStatements(funcProp.propertyName.text(), funcProp,
- funcProp.callSignature.parameterList.parameters, funcProp.block, /*bodyExpression:*/ null);
-
- this.recordSourceMappingEnd(funcProp);
-
- // The extra call is to make sure the caller's funcDecl end is recorded, since caller wont be able to record it
- this.recordSourceMappingEnd(funcProp);
-
- this.emitComments(funcProp, false);
-
- this.popDecl(pullDecl);
-
- this.setContainer(temp);
- this.inArrowFunction = savedInArrowFunction;
- }
-
- public emitConditionalExpression(expression: ConditionalExpressionSyntax): void {
- this.emit(expression.condition);
- this.writeToOutput(" ");
- this.writeToken(expression.questionToken);
- this.writeToOutput(" ");
- this.emit(expression.whenTrue);
- this.writeToOutput(" ");
- this.writeToken(expression.colonToken);
- this.writeToOutput(" ");
- this.emit(expression.whenFalse);
- }
-
- public emitThrowStatement(statement: ThrowStatementSyntax): void {
- this.recordSourceMappingStart(statement);
- this.writeToken(statement.throwKeyword);
- this.writeToOutput(" ");
- this.emit(statement.expression);
- this.writeToOutputWithSourceMapRecord(";", statement.semicolonToken);
- this.recordSourceMappingEnd(statement);
- }
-
- public emitExpressionStatement(statement: ExpressionStatementSyntax): void {
- var isArrowExpression = statement.expression.kind() === SyntaxKind.SimpleArrowFunctionExpression || statement.expression.kind() === SyntaxKind.ParenthesizedArrowFunctionExpression;
-
- this.recordSourceMappingStart(statement);
- if (isArrowExpression) {
- this.writeToOutput("(");
- }
-
- this.emit(statement.expression);
-
- if (isArrowExpression) {
- this.writeToOutput(")");
- }
-
- this.writeToOutputWithSourceMapRecord(";", statement.semicolonToken);
- this.recordSourceMappingEnd(statement);
- }
-
- public emitLabeledStatement(statement: LabeledStatementSyntax): void {
- this.writeToOutputWithSourceMapRecord(statement.identifier.text(), statement.identifier);
- this.writeToken(statement.colonToken);
- this.writeLineToOutput("");
- this.emitJavascript(statement.statement, /*startLine:*/ true);
- }
-
- public emitBlock(block: BlockSyntax): void {
- this.recordSourceMappingStart(block);
- this.writeLineToOutput(" {");
- this.indenter.increaseIndent();
- if (block.statements) {
- this.emitList(block.statements);
- }
- this.emitCommentsArray(ASTHelpers.convertTokenLeadingComments(block.closeBraceToken, this.text()), /*trailing:*/ false);
- this.indenter.decreaseIndent();
- this.emitIndent();
- this.writeToken(block.closeBraceToken);
- this.recordSourceMappingEnd(block);
- }
-
- public emitBreakStatement(jump: BreakStatementSyntax): void {
- this.recordSourceMappingStart(jump);
- this.writeToken(jump.breakKeyword);
-
- if (jump.identifier) {
- this.writeToOutput(" ");
- this.writeToOutputWithSourceMapRecord(jump.identifier.text(), jump.identifier);
- }
-
- this.writeToOutputWithSourceMapRecord(";", jump.semicolonToken);
- this.recordSourceMappingEnd(jump);
- }
-
- public emitContinueStatement(jump: ContinueStatementSyntax): void {
- this.recordSourceMappingStart(jump);
- this.writeToken(jump.continueKeyword);
-
- if (jump.identifier) {
- this.writeToOutput(" ");
- this.writeToOutputWithSourceMapRecord(jump.identifier.text(), jump.identifier);
- }
-
- this.writeToOutputWithSourceMapRecord(";", jump.semicolonToken);
- this.recordSourceMappingEnd(jump);
- }
-
- public emitWhileStatement(statement: WhileStatementSyntax): void {
- this.recordSourceMappingStart(statement);
- this.writeToken(statement.whileKeyword);
- this.writeToOutput(" ");
- this.writeToken(statement.openParenToken);
- this.emit(statement.condition);
- this.writeToken(statement.closeParenToken);
- this.emitBlockOrStatement(statement.statement);
- this.recordSourceMappingEnd(statement);
- }
-
- public emitDoStatement(statement: DoStatementSyntax): void {
- this.recordSourceMappingStart(statement);
- this.writeToken(statement.doKeyword);
- this.emitBlockOrStatement(statement.statement);
- this.writeToOutput(" ");
- this.writeToken(statement.whileKeyword);
- this.writeToken(statement.openParenToken);
- this.emit(statement.condition);
- this.writeToken(statement.closeParenToken);
- this.writeToOutputWithSourceMapRecord(";", statement.semicolonToken);
- this.recordSourceMappingEnd(statement);
- }
-
- public emitIfStatement(statement: IfStatementSyntax): void {
- this.recordSourceMappingStart(statement);
- this.writeToken(statement.ifKeyword);
- this.writeToOutput(" ");
- this.writeToken(statement.openParenToken);
- this.emit(statement.condition);
- this.writeToken(statement.closeParenToken);
-
- this.emitBlockOrStatement(statement.statement);
-
- if (statement.elseClause) {
- if (statement.statement.kind() !== SyntaxKind.Block) {
- this.writeLineToOutput("");
- this.emitIndent();
- }
- else {
- this.writeToOutput(" ");
- }
-
- this.emit(statement.elseClause);
- }
- this.recordSourceMappingEnd(statement);
- }
-
- public emitElseClause(elseClause: ElseClauseSyntax): void {
- this.writeToken(elseClause.elseKeyword);
- if (elseClause.statement.kind() === SyntaxKind.IfStatement) {
- this.writeToOutput(" ");
- this.emit(elseClause.statement);
- }
- else {
- this.emitBlockOrStatement(elseClause.statement);
- }
- }
-
- public emitReturnStatement(statement: ReturnStatementSyntax): void {
- this.recordSourceMappingStart(statement);
- this.writeToken(statement.returnKeyword);
- if (statement.expression) {
- this.writeToOutput(" ");
- this.emit(statement.expression);
- }
-
- this.writeToOutputWithSourceMapRecord(";", statement.semicolonToken);
- this.recordSourceMappingEnd(statement);
- }
-
- public emitForInStatement(statement: ForInStatementSyntax): void {
- this.recordSourceMappingStart(statement);
- this.writeToken(statement.forKeyword);
- this.writeToOutput(" ");
- this.writeToken(statement.openParenToken);
-
- if (statement.left) {
- this.emit(statement.left);
- }
- else {
- this.emit(statement.variableDeclaration);
- }
- this.writeToOutput(" ");
- this.writeToken(statement.inKeyword);
- this.writeToOutput(" ");
- this.emit(statement.expression);
- this.writeToken(statement.closeParenToken);
- this.emitBlockOrStatement(statement.statement);
- this.recordSourceMappingEnd(statement);
- }
-
- public emitForStatement(statement: ForStatementSyntax): void {
- this.recordSourceMappingStart(statement);
- this.writeToken(statement.forKeyword);
- this.writeToOutput(" ");
- this.writeToken(statement.openParenToken);
-
- if (statement.variableDeclaration) {
- this.emit(statement.variableDeclaration);
- }
- else if (statement.initializer) {
- this.emit(statement.initializer);
- }
-
- this.writeToken(statement.firstSemicolonToken);
- this.writeToOutput(" ");
- this.emitJavascript(statement.condition, false);
- this.writeToken(statement.secondSemicolonToken);
- if (statement.incrementor) {
- this.writeToOutput(" ");
- this.emitJavascript(statement.incrementor, false);
- }
- this.writeToken(statement.closeParenToken);
- this.emitBlockOrStatement(statement.statement);
- this.recordSourceMappingEnd(statement);
- }
-
- public emitWithStatement(statement: WithStatementSyntax): void {
- this.recordSourceMappingStart(statement);
- this.writeToken(statement.withKeyword);
- this.writeToOutput(" ");
- this.writeToken(statement.openParenToken);
- if (statement.condition) {
- this.emit(statement.condition);
- }
-
- this.writeToken(statement.closeParenToken);
- var prevInWithBlock = this.inWithBlock;
- this.inWithBlock = true;
- this.emitBlockOrStatement(statement.statement);
- this.inWithBlock = prevInWithBlock;
- this.recordSourceMappingEnd(statement);
- }
-
- public emitSwitchStatement(statement: SwitchStatementSyntax): void {
- this.recordSourceMappingStart(statement);
- this.writeToken(statement.switchKeyword);
- this.writeToOutput(" ");
- this.writeToken(statement.openParenToken);
- this.emit(statement.expression);
- this.writeToken(statement.closeParenToken);
- this.writeLineToOutput(" {");
- this.indenter.increaseIndent();
- this.emitList(statement.switchClauses, /*useNewLineSeparator:*/ false);
- this.indenter.decreaseIndent();
- this.emitIndent();
- this.writeToken(statement.closeBraceToken);
- this.recordSourceMappingEnd(statement);
- }
-
- public emitCaseSwitchClause(clause: CaseSwitchClauseSyntax): void {
- this.recordSourceMappingStart(clause);
- this.writeToken(clause.caseKeyword);
- this.writeToOutput(" ");
- this.emit(clause.expression);
- this.writeToken(clause.colonToken);
-
- this.emitSwitchClauseBody(clause.colonToken, clause.statements);
- this.recordSourceMappingEnd(clause);
- }
-
- private emitSwitchClauseBody(colonToken: ISyntaxToken, body: IStatementSyntax[]): void {
- var text = this.text();
- if (body.length === 1 && childAt(body, 0).kind() === SyntaxKind.Block) {
- // The case statement was written with curly braces, so emit it with the appropriate formatting
- this.emit(childAt(body, 0));
- this.writeLineToOutput("");
- }
- else if (body.length === 1 && this.isOnSameLine(end(colonToken, text), start(body[0], text))) {
- this.writeToOutput(" ");
- this.emit(childAt(body, 0));
- this.writeLineToOutput("");
- }
- else {
- // No curly braces. Format in the expected way
- this.writeLineToOutput("");
- this.indenter.increaseIndent();
- this.emit(body);
- this.indenter.decreaseIndent();
- }
- }
-
- public emitDefaultSwitchClause(clause: DefaultSwitchClauseSyntax): void {
- this.recordSourceMappingStart(clause);
- this.writeToken(clause.defaultKeyword);
- this.writeToken(clause.colonToken);
-
- this.emitSwitchClauseBody(clause.colonToken, clause.statements);
- this.recordSourceMappingEnd(clause);
- }
-
- public emitTryStatement(statement: TryStatementSyntax): void {
- this.recordSourceMappingStart(statement);
- this.writeToken(statement.tryKeyword);
- this.writeToOutput(" ");
- this.emit(statement.block);
- this.emitJavascript(statement.catchClause, false);
-
- if (statement.finallyClause) {
- this.emit(statement.finallyClause);
- }
- this.recordSourceMappingEnd(statement);
- }
-
- public emitCatchClause(clause: CatchClauseSyntax): void {
- this.writeToOutput(" ");
- this.recordSourceMappingStart(clause);
- this.writeToken(clause.catchKeyword);
- this.writeToOutput(" ");
- this.writeToken(clause.openParenToken);
- this.emit(clause.identifier);
- this.writeToken(clause.closeParenToken);
- this.emit(clause.block);
- this.recordSourceMappingEnd(clause);
- }
-
- public emitFinallyClause(clause: FinallyClauseSyntax): void {
- this.writeToOutput(" ");
- this.writeToken(clause.finallyKeyword);
- this.emit(clause.block);
- }
-
- public emitDebuggerStatement(statement: DebuggerStatementSyntax): void {
- this.writeToken(statement.debuggerKeyword);
- this.writeToOutputWithSourceMapRecord(";", statement.semicolonToken);
- }
-
- public emitNumericLiteral(literal: ISyntaxToken): void {
- this.writeToOutputWithSourceMapRecord(literal.text(), literal);
- }
-
- public emitRegularExpressionLiteral(literal: ISyntaxToken): void {
- this.writeToOutputWithSourceMapRecord(literal.text(), literal);
- }
-
- public emitStringLiteral(literal: ISyntaxToken): void {
- this.writeToOutputWithSourceMapRecord(literal.text(), literal);
- }
-
- public emitEqualsValueClause(clause: EqualsValueClauseSyntax): void {
- this.writeToOutput(" ");
- this.writeToken(clause.equalsToken);
- this.writeToOutput(" ");
- this.emitCommentsArray(ASTHelpers.convertTokenTrailingComments(clause.equalsToken, this.text()), /*trailing:*/ true, /*noLeadingSpace:*/ true);
-
- this.emit(clause.value);
- }
-
- private emitParameter(parameter: ParameterSyntax): void {
- this.writeToOutputWithSourceMapRecord(parameter.identifier.text(), parameter);
- }
-
- public emitConstructorDeclaration(declaration: ConstructorDeclarationSyntax): void {
- if (declaration.block) {
- this.emitConstructor(declaration);
- }
- else {
- this.emitComments(declaration, /*pre:*/ true, /*onlyPinnedOrTripleSlashComments:*/ true);
- }
- }
-
- public shouldEmitFunctionDeclaration(declaration: FunctionDeclarationSyntax): boolean {
- return ASTHelpers.preComments(declaration, this.text()) !== null || (!hasModifier(declaration.modifiers, PullElementFlags.Ambient) && declaration.block !== null);
- }
-
- public emitFunctionDeclaration(declaration: FunctionDeclarationSyntax): void {
- if (!hasModifier(declaration.modifiers, PullElementFlags.Ambient) && declaration.block !== null) {
- this.emitFunction(declaration);
- }
- else {
- this.emitComments(declaration, /*pre:*/ true, /*onlyPinnedOrTripleSlashComments:*/ true);
- }
- }
-
- private emitSourceUnit(sourceUnit: SourceUnitSyntax): void {
- if (!this.document.isDeclareFile()) {
- var pullDecl = this.semanticInfoChain.getDeclForAST(sourceUnit);
- this.pushDecl(pullDecl);
- this.emitScriptElements(sourceUnit);
- this.popDecl(pullDecl);
-
- this.emitCommentsArray(ASTHelpers.convertTokenLeadingComments(sourceUnit.endOfFileToken, this.text()), /*trailing:*/ false);
- }
- }
-
- public shouldEmitEnumDeclaration(declaration: EnumDeclarationSyntax): boolean {
- return ASTHelpers.preComments(declaration, this.text()) !== null || !ASTHelpers.enumIsElided(declaration);
- }
-
- public emitEnumDeclaration(declaration: EnumDeclarationSyntax): void {
- if (!ASTHelpers.enumIsElided(declaration)) {
- this.emitComments(declaration, true);
- this.emitEnum(declaration);
- this.emitComments(declaration, false);
- }
- else {
- this.emitComments(declaration, true, /*onlyPinnedOrTripleSlashComments:*/ true);
- }
- }
-
- public shouldEmitModuleDeclaration(declaration: ModuleDeclarationSyntax): boolean {
- return ASTHelpers.preComments(declaration, this.text()) !== null || !ASTHelpers.moduleIsElided(declaration);
- }
-
- private emitModuleDeclaration(declaration: ModuleDeclarationSyntax): void {
- if (!ASTHelpers.moduleIsElided(declaration)) {
- this.emitModuleDeclarationWorker(declaration);
- }
- else {
- this.emitComments(declaration, true, /*onlyPinnedOrTripleSlashComments:*/ true);
- }
- }
-
- public shouldEmitClassDeclaration(declaration: ClassDeclarationSyntax): boolean {
- return ASTHelpers.preComments(declaration, this.text()) !== null || !hasModifier(declaration.modifiers, PullElementFlags.Ambient);
- }
-
- public emitClassDeclaration(declaration: ClassDeclarationSyntax): void {
- if (!hasModifier(declaration.modifiers, PullElementFlags.Ambient)) {
- this.emitClass(declaration);
- }
- else {
- this.emitComments(declaration, /*pre:*/ true, /*onlyPinnedOrTripleSlashComments:*/ true);
- }
- }
-
- public shouldEmitInterfaceDeclaration(declaration: InterfaceDeclarationSyntax): boolean {
- return ASTHelpers.preComments(declaration, this.text()) !== null;
- }
-
- public emitInterfaceDeclaration(declaration: InterfaceDeclarationSyntax): void {
- this.emitComments(declaration, /*pre:*/ true, /*onlyPinnedOrTripleSlashComments:*/ true);
- }
-
- private firstVariableDeclarator(statement: VariableStatementSyntax): VariableDeclaratorSyntax {
- return statement.variableDeclaration.variableDeclarators[0];
- }
-
- private isNotAmbientOrHasInitializer(variableStatement: VariableStatementSyntax): boolean {
- return !hasModifier(variableStatement.modifiers, PullElementFlags.Ambient) || this.firstVariableDeclarator(variableStatement).equalsValueClause !== null;
- }
-
- public shouldEmitVariableStatement(statement: VariableStatementSyntax): boolean {
- return ASTHelpers.preComments(statement, this.text()) !== null || this.isNotAmbientOrHasInitializer(statement);
- }
-
- public emitVariableStatement(statement: VariableStatementSyntax): void {
- if (this.isNotAmbientOrHasInitializer(statement)) {
- this.emitComments(statement, true);
- this.emit(statement.variableDeclaration);
- this.writeToOutputWithSourceMapRecord(";", statement.semicolonToken);
- this.emitComments(statement, false);
- }
- else {
- this.emitComments(statement, /*pre:*/ true, /*onlyPinnedOrTripleSlashComments:*/ true);
- }
- }
-
- public emitGenericType(type: GenericTypeSyntax): void {
- this.emit(type.name);
- }
-
- private shouldEmit(ast: ISyntaxElement): boolean {
- if (!ast) {
- return false;
- }
-
- switch (ast.kind()) {
- case SyntaxKind.ImportDeclaration:
- return this.shouldEmitImportDeclaration(ast);
- case SyntaxKind.ClassDeclaration:
- return this.shouldEmitClassDeclaration(ast);
- case SyntaxKind.InterfaceDeclaration:
- return this.shouldEmitInterfaceDeclaration(ast);
- case SyntaxKind.FunctionDeclaration:
- return this.shouldEmitFunctionDeclaration(ast);
- case SyntaxKind.ModuleDeclaration:
- return this.shouldEmitModuleDeclaration(ast);
- case SyntaxKind.VariableStatement:
- return this.shouldEmitVariableStatement(ast);
- case SyntaxKind.OmittedExpression:
- return false;
- case SyntaxKind.EnumDeclaration:
- return this.shouldEmitEnumDeclaration(ast);
- }
-
- return true;
- }
-
- private emit(ast: ISyntaxElement): void {
- if (!ast) {
- return;
- }
-
- switch (ast.kind()) {
- case SyntaxKind.SeparatedList:
- return this.emitSeparatedList(ast);
- case SyntaxKind.List:
- return this.emitList(ast);
- case SyntaxKind.SourceUnit:
- return this.emitSourceUnit(ast);
- case SyntaxKind.ImportDeclaration:
- return this.emitImportDeclaration(ast);
- case SyntaxKind.ExportAssignment:
- return this.setExportAssignment(ast);
- case SyntaxKind.ClassDeclaration:
- return this.emitClassDeclaration(ast);
- case SyntaxKind.InterfaceDeclaration:
- return this.emitInterfaceDeclaration(ast);
- case SyntaxKind.IdentifierName:
- return this.emitName(ast, true);
- case SyntaxKind.VariableDeclarator:
- return this.emitVariableDeclarator(ast);
- case SyntaxKind.SimpleArrowFunctionExpression:
- return this.emitSimpleArrowFunctionExpression(ast);
- case SyntaxKind.ParenthesizedArrowFunctionExpression:
- return this.emitParenthesizedArrowFunctionExpression(ast);
- case SyntaxKind.FunctionDeclaration:
- return this.emitFunctionDeclaration(ast);
- case SyntaxKind.ModuleDeclaration:
- return this.emitModuleDeclaration(ast);
- case SyntaxKind.VariableDeclaration:
- return this.emitVariableDeclaration(ast);
- case SyntaxKind.GenericType:
- return this.emitGenericType(ast);
- case SyntaxKind.ConstructorDeclaration:
- return this.emitConstructorDeclaration(ast);
- case SyntaxKind.EnumDeclaration:
- return this.emitEnumDeclaration(ast);
- case SyntaxKind.EnumElement:
- return this.emitEnumElement(ast);
- case SyntaxKind.FunctionExpression:
- return this.emitFunctionExpression(ast);
- case SyntaxKind.VariableStatement:
- return this.emitVariableStatement(ast);
- }
-
- this.emitComments(ast, true);
- this.emitWorker(ast);
- this.emitComments(ast, false);
- }
-
- private emitWorker(ast: ISyntaxElement): void {
- if (!ast) {
- return;
- }
-
- switch (ast.kind()) {
- case SyntaxKind.NumericLiteral:
- return this.emitNumericLiteral(ast);
- case SyntaxKind.RegularExpressionLiteral:
- return this.emitRegularExpressionLiteral(ast);
- case SyntaxKind.StringLiteral:
- return this.emitStringLiteral(ast);
- case SyntaxKind.FalseKeyword:
- case SyntaxKind.NullKeyword:
- case SyntaxKind.TrueKeyword:
- return this.emitLiteralExpression(ast);
- case SyntaxKind.ThisKeyword:
- return this.emitThisExpression(ast);
- case SyntaxKind.SuperKeyword:
- return this.emitSuperExpression(ast);
- case SyntaxKind.ParenthesizedExpression:
- return this.emitParenthesizedExpression(ast);
- case SyntaxKind.ArrayLiteralExpression:
- return this.emitArrayLiteralExpression(ast);
- case SyntaxKind.PostDecrementExpression:
- case SyntaxKind.PostIncrementExpression:
- return this.emitPostfixUnaryExpression(ast);
- case SyntaxKind.LogicalNotExpression:
- case SyntaxKind.BitwiseNotExpression:
- case SyntaxKind.NegateExpression:
- case SyntaxKind.PlusExpression:
- case SyntaxKind.PreIncrementExpression:
- case SyntaxKind.PreDecrementExpression:
- return this.emitPrefixUnaryExpression(ast);
- case SyntaxKind.InvocationExpression:
- return this.emitInvocationExpression(ast);
- case SyntaxKind.ElementAccessExpression:
- return this.emitElementAccessExpression(ast);
- case SyntaxKind.MemberAccessExpression:
- return this.emitMemberAccessExpression(ast);
- case SyntaxKind.QualifiedName:
- return this.emitQualifiedName(ast);
- case SyntaxKind.CommaExpression:
- 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.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 this.emitBinaryExpression(ast);
- case SyntaxKind.ConditionalExpression:
- return this.emitConditionalExpression(ast);
- case SyntaxKind.EqualsValueClause:
- return this.emitEqualsValueClause(ast);
- case SyntaxKind.Parameter:
- return this.emitParameter(ast);
- case SyntaxKind.Block:
- return this.emitBlock(ast);
- case SyntaxKind.ElseClause:
- return this.emitElseClause(ast);
- case SyntaxKind.IfStatement:
- return this.emitIfStatement(ast);
- case SyntaxKind.ExpressionStatement:
- return this.emitExpressionStatement(ast);
- case SyntaxKind.GetAccessor:
- return this.emitGetAccessor(ast);
- case SyntaxKind.SetAccessor:
- return this.emitSetAccessor(ast);
- case SyntaxKind.ThrowStatement:
- return this.emitThrowStatement(ast);
- case SyntaxKind.ReturnStatement:
- return this.emitReturnStatement(ast);
- case SyntaxKind.ObjectCreationExpression:
- return this.emitObjectCreationExpression(ast);
- case SyntaxKind.SwitchStatement:
- return this.emitSwitchStatement(ast);
- case SyntaxKind.CaseSwitchClause:
- return this.emitCaseSwitchClause(ast);
- case SyntaxKind.DefaultSwitchClause:
- return this.emitDefaultSwitchClause(ast);
- case SyntaxKind.BreakStatement:
- return this.emitBreakStatement(ast);
- case SyntaxKind.ContinueStatement:
- return this.emitContinueStatement(ast);
- case SyntaxKind.ForStatement:
- return this.emitForStatement(ast);
- case SyntaxKind.ForInStatement:
- return this.emitForInStatement(ast);
- case SyntaxKind.WhileStatement:
- return this.emitWhileStatement(ast);
- case SyntaxKind.WithStatement:
- return this.emitWithStatement(ast);
- case SyntaxKind.CastExpression:
- return this.emitCastExpression(ast);
- case SyntaxKind.ObjectLiteralExpression:
- return this.emitObjectLiteralExpression(ast);
- case SyntaxKind.SimplePropertyAssignment:
- return this.emitSimplePropertyAssignment(ast);
- case SyntaxKind.FunctionPropertyAssignment:
- return this.emitFunctionPropertyAssignment(ast);
- case SyntaxKind.EmptyStatement:
- return this.writeToken((ast).semicolonToken);
- case SyntaxKind.TryStatement:
- return this.emitTryStatement(ast);
- case SyntaxKind.CatchClause:
- return this.emitCatchClause(ast);
- case SyntaxKind.FinallyClause:
- return this.emitFinallyClause(ast);
- case SyntaxKind.LabeledStatement:
- return this.emitLabeledStatement(ast);
- case SyntaxKind.DoStatement:
- return this.emitDoStatement(ast);
- case SyntaxKind.TypeOfExpression:
- return this.emitTypeOfExpression(ast);
- case SyntaxKind.DeleteExpression:
- return this.emitDeleteExpression(ast);
- case SyntaxKind.VoidExpression:
- return this.emitVoidExpression(ast);
- case SyntaxKind.DebuggerStatement:
- return this.emitDebuggerStatement(ast);
- }
- }
- }
-
- export function getLastConstructor(classDecl: ClassDeclarationSyntax): ConstructorDeclarationSyntax {
- for (var i = classDecl.classElements.length - 1; i >= 0; i--) {
- var child = classDecl.classElements[i];
-
- if (child.kind() === SyntaxKind.ConstructorDeclaration) {
- return child;
- }
- }
-
- return null;
- }
-
- export function getTrimmedTextLines(comment: Comment): string[] {
- if (comment.kind() === SyntaxKind.MultiLineCommentTrivia) {
- return comment.fullText().split("\n").map(s => s.trim());
- }
- else {
- return [comment.fullText().trim()];
- }
- }
-}
\ No newline at end of file
diff --git a/src/services/compiler/optionsParser.ts b/src/services/compiler/optionsParser.ts
deleted file mode 100644
index 6c2a15813d5..00000000000
--- a/src/services/compiler/optionsParser.ts
+++ /dev/null
@@ -1,266 +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.
-//
-
-///
-
-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 = 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 = 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);
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/services/compiler/tsc.ts b/src/services/compiler/tsc.ts
deleted file mode 100644
index acd4fb40e6a..00000000000
--- a/src/services/compiler/tsc.ts
+++ /dev/null
@@ -1,736 +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.
-//
-
-///
-///
-///
-
-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();
- 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.Raise_error_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();
-
- // 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();
-
- 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();
-
- 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();
-}
diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts
index 9051ee80399..423ee5e58a6 100644
--- a/src/services/navigationBar.ts
+++ b/src/services/navigationBar.ts
@@ -50,8 +50,9 @@ module ts.NavigationBar {
case SyntaxKind.ArrayBindingPattern:
forEach((node).elements, visit);
break;
+ case SyntaxKind.BindingElement:
case SyntaxKind.VariableDeclaration:
- if (isBindingPattern(node)) {
+ if (isBindingPattern((node).name)) {
visit((node).name);
break;
}
@@ -262,17 +263,34 @@ module ts.NavigationBar {
return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.functionElement);
case SyntaxKind.VariableDeclaration:
- if (isBindingPattern((node).name)) {
- break;
- }
- if (isConst(node)) {
- return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.constElement);
- }
- else if (isLet(node)) {
- return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.letElement);
+ case SyntaxKind.BindingElement:
+ var variableDeclarationNode: Node;
+ var name: Node;
+
+ if (node.kind === SyntaxKind.BindingElement) {
+ name = (node).name;
+ variableDeclarationNode = node;
+ // binding elements are added only for variable declarations
+ // bubble up to the containing variable declaration
+ while (variableDeclarationNode && variableDeclarationNode.kind !== SyntaxKind.VariableDeclaration) {
+ variableDeclarationNode = variableDeclarationNode.parent;
+ }
+ Debug.assert(variableDeclarationNode !== undefined);
}
else {
- return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.variableElement);
+ Debug.assert(!isBindingPattern((node).name));
+ variableDeclarationNode = node;
+ name = (node).name;
+ }
+
+ if (isConst(variableDeclarationNode)) {
+ return createItem(node, getTextOfNode(name), ts.ScriptElementKind.constElement);
+ }
+ else if (isLet(variableDeclarationNode)) {
+ return createItem(node, getTextOfNode(name), ts.ScriptElementKind.letElement);
+ }
+ else {
+ return createItem(node, getTextOfNode(name), ts.ScriptElementKind.variableElement);
}
case SyntaxKind.Constructor:
diff --git a/src/services/resources/diagnosticCode.generated.ts b/src/services/resources/diagnosticCode.generated.ts
index 86509fdd63b..1a0ac12e165 100644
--- a/src/services/resources/diagnosticCode.generated.ts
+++ b/src/services/resources/diagnosticCode.generated.ts
@@ -402,19 +402,13 @@ module TypeScript {
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",
@@ -431,7 +425,6 @@ module TypeScript {
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.",
diff --git a/src/services/services.ts b/src/services/services.ts
index 662ae7df102..1c6f9859c7e 100644
--- a/src/services/services.ts
+++ b/src/services/services.ts
@@ -59,7 +59,7 @@ module ts {
isOpen: boolean;
version: string;
scriptSnapshot: IScriptSnapshot;
-
+ nameTable: Map;
getNamedDeclarations(): Declaration[];
}
@@ -335,36 +335,44 @@ module ts {
var paramTag = "@param";
var jsDocCommentParts: SymbolDisplayPart[] = [];
- ts.forEach(declarations, declaration => {
- var sourceFileOfDeclaration = getSourceFileOfNode(declaration);
- // If it is parameter - try and get the jsDoc comment with @param tag from function declaration's jsDoc comments
- if (canUseParsedParamTagComments && declaration.kind === SyntaxKind.Parameter) {
- ts.forEach(getJsDocCommentTextRange(declaration.parent, sourceFileOfDeclaration), jsDocCommentTextRange => {
- var cleanedParamJsDocComment = getCleanedParamJsDocComment(jsDocCommentTextRange.pos, jsDocCommentTextRange.end, sourceFileOfDeclaration);
- if (cleanedParamJsDocComment) {
- jsDocCommentParts.push.apply(jsDocCommentParts, cleanedParamJsDocComment);
- }
- });
+ ts.forEach(declarations, (declaration, indexOfDeclaration) => {
+ // Make sure we are collecting doc comment from declaration once,
+ // In case of union property there might be same declaration multiple times
+ // which only varies in type parameter
+ // Eg. var a: Array | Array; a.length
+ // The property length will have two declarations of property length coming
+ // from Array - Array and Array
+ if (indexOf(declarations, declaration) === indexOfDeclaration) {
+ var sourceFileOfDeclaration = getSourceFileOfNode(declaration);
+ // If it is parameter - try and get the jsDoc comment with @param tag from function declaration's jsDoc comments
+ if (canUseParsedParamTagComments && declaration.kind === SyntaxKind.Parameter) {
+ ts.forEach(getJsDocCommentTextRange(declaration.parent, sourceFileOfDeclaration), jsDocCommentTextRange => {
+ var cleanedParamJsDocComment = getCleanedParamJsDocComment(jsDocCommentTextRange.pos, jsDocCommentTextRange.end, sourceFileOfDeclaration);
+ if (cleanedParamJsDocComment) {
+ jsDocCommentParts.push.apply(jsDocCommentParts, cleanedParamJsDocComment);
+ }
+ });
+ }
+
+ // If this is left side of dotted module declaration, there is no doc comments associated with this node
+ if (declaration.kind === SyntaxKind.ModuleDeclaration && (