mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into relativePathReferenceResolution
This commit is contained in:
Vendored
+4
@@ -499,6 +499,10 @@ declare var Number: {
|
||||
POSITIVE_INFINITY: number;
|
||||
}
|
||||
|
||||
interface TemplateStringsArray extends Array<string> {
|
||||
raw: string[];
|
||||
}
|
||||
|
||||
interface Math {
|
||||
/** The mathematical constant e. This is Euler's number, the base of natural logarithms. */
|
||||
E: number;
|
||||
|
||||
Vendored
+4
@@ -499,6 +499,10 @@ declare var Number: {
|
||||
POSITIVE_INFINITY: number;
|
||||
}
|
||||
|
||||
interface TemplateStringsArray extends Array<string> {
|
||||
raw: string[];
|
||||
}
|
||||
|
||||
interface Math {
|
||||
/** The mathematical constant e. This is Euler's number, the base of natural logarithms. */
|
||||
E: number;
|
||||
|
||||
+2665
-2366
File diff suppressed because one or more lines are too long
+5141
-17281
File diff suppressed because one or more lines are too long
+46
-9
@@ -93,10 +93,16 @@ module ts {
|
||||
return (<Identifier>node.name).text;
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Constructor: return "__constructor";
|
||||
case SyntaxKind.CallSignature: return "__call";
|
||||
case SyntaxKind.ConstructSignature: return "__new";
|
||||
case SyntaxKind.IndexSignature: return "__index";
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.Constructor:
|
||||
return "__constructor";
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.CallSignature:
|
||||
return "__call";
|
||||
case SyntaxKind.ConstructSignature:
|
||||
return "__new";
|
||||
case SyntaxKind.IndexSignature:
|
||||
return "__index";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,8 +120,11 @@ module ts {
|
||||
}
|
||||
// Report errors every position with duplicate declaration
|
||||
// Report errors on previous encountered declarations
|
||||
var message = symbol.flags & SymbolFlags.BlockScopedVariable ? Diagnostics.Cannot_redeclare_block_scoped_variable_0 : Diagnostics.Duplicate_identifier_0;
|
||||
forEach(symbol.declarations, (declaration) => {
|
||||
var message = symbol.flags & SymbolFlags.BlockScopedVariable
|
||||
? Diagnostics.Cannot_redeclare_block_scoped_variable_0
|
||||
: Diagnostics.Duplicate_identifier_0;
|
||||
|
||||
forEach(symbol.declarations, declaration => {
|
||||
file.semanticErrors.push(createDiagnosticForNode(declaration.name, message, getDisplayName(declaration)));
|
||||
});
|
||||
file.semanticErrors.push(createDiagnosticForNode(node.name, message, getDisplayName(node)));
|
||||
@@ -233,6 +242,8 @@ module ts {
|
||||
declareModuleMember(node, symbolKind, symbolExcludes);
|
||||
break;
|
||||
}
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.IndexSignature:
|
||||
@@ -294,6 +305,25 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function bindFunctionOrConstructorType(node: SignatureDeclaration) {
|
||||
// For a given function symbol "<...>(...) => T" we want to generate a symbol identical
|
||||
// to the one we would get for: { <...>(...): T }
|
||||
//
|
||||
// We do that by making an anonymous type literal symbol, and then setting the function
|
||||
// symbol as its sole member. To the rest of the system, this symbol will be indistinguishable
|
||||
// from an actual type literal symbol you would have gotten had you used the long form.
|
||||
|
||||
var symbolKind = node.kind === SyntaxKind.FunctionType ? SymbolFlags.CallSignature : SymbolFlags.ConstructSignature;
|
||||
var symbol = createSymbol(symbolKind, getDeclarationName(node));
|
||||
addDeclarationToSymbol(symbol, node, symbolKind);
|
||||
bindChildren(node, symbolKind, /*isBlockScopeContainer:*/ false);
|
||||
|
||||
var typeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral, "__type");
|
||||
addDeclarationToSymbol(typeLiteralSymbol, node, SymbolFlags.TypeLiteral);
|
||||
typeLiteralSymbol.members = {};
|
||||
typeLiteralSymbol.members[node.kind === SyntaxKind.FunctionType ? "__call" : "__new"] = symbol
|
||||
}
|
||||
|
||||
function bindAnonymousDeclaration(node: Node, symbolKind: SymbolFlags, name: string, isBlockScopeContainer: boolean) {
|
||||
var symbol = createSymbol(symbolKind, name);
|
||||
addDeclarationToSymbol(symbol, node, symbolKind);
|
||||
@@ -350,6 +380,7 @@ module ts {
|
||||
break;
|
||||
case SyntaxKind.Property:
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
bindDeclaration(<Declaration>node, SymbolFlags.Property, SymbolFlags.PropertyExcludes, /*isBlockScopeContainer*/ false);
|
||||
break;
|
||||
case SyntaxKind.EnumMember:
|
||||
@@ -358,12 +389,12 @@ module ts {
|
||||
case SyntaxKind.CallSignature:
|
||||
bindDeclaration(<Declaration>node, SymbolFlags.CallSignature, 0, /*isBlockScopeContainer*/ false);
|
||||
break;
|
||||
case SyntaxKind.Method:
|
||||
bindDeclaration(<Declaration>node, SymbolFlags.Method, SymbolFlags.MethodExcludes, /*isBlockScopeContainer*/ true);
|
||||
break;
|
||||
case SyntaxKind.ConstructSignature:
|
||||
bindDeclaration(<Declaration>node, SymbolFlags.ConstructSignature, 0, /*isBlockScopeContainer*/ true);
|
||||
break;
|
||||
case SyntaxKind.Method:
|
||||
bindDeclaration(<Declaration>node, SymbolFlags.Method, SymbolFlags.MethodExcludes, /*isBlockScopeContainer*/ true);
|
||||
break;
|
||||
case SyntaxKind.IndexSignature:
|
||||
bindDeclaration(<Declaration>node, SymbolFlags.IndexSignature, 0, /*isBlockScopeContainer*/ false);
|
||||
break;
|
||||
@@ -379,6 +410,12 @@ module ts {
|
||||
case SyntaxKind.SetAccessor:
|
||||
bindDeclaration(<Declaration>node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes, /*isBlockScopeContainer*/ true);
|
||||
break;
|
||||
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
bindFunctionOrConstructorType(<SignatureDeclaration>node);
|
||||
break;
|
||||
|
||||
case SyntaxKind.TypeLiteral:
|
||||
bindAnonymousDeclaration(node, SymbolFlags.TypeLiteral, "__type", /*isBlockScopeContainer*/ false);
|
||||
break;
|
||||
|
||||
+145
-77
@@ -75,41 +75,43 @@ module ts {
|
||||
|
||||
var checker: TypeChecker = {
|
||||
getProgram: () => program,
|
||||
getDiagnostics: getDiagnostics,
|
||||
getGlobalDiagnostics: getGlobalDiagnostics,
|
||||
getNodeCount: () => sum(program.getSourceFiles(), "nodeCount"),
|
||||
getIdentifierCount: () => sum(program.getSourceFiles(), "identifierCount"),
|
||||
getSymbolCount: () => sum(program.getSourceFiles(), "symbolCount"),
|
||||
getTypeCount: () => typeCount,
|
||||
checkProgram: checkProgram,
|
||||
emitFiles: invokeEmitter,
|
||||
getParentOfSymbol: getParentOfSymbol,
|
||||
getNarrowedTypeOfSymbol: getNarrowedTypeOfSymbol,
|
||||
getDeclaredTypeOfSymbol: getDeclaredTypeOfSymbol,
|
||||
getPropertiesOfType: getPropertiesOfType,
|
||||
getPropertyOfType: getPropertyOfType,
|
||||
getSignaturesOfType: getSignaturesOfType,
|
||||
getIndexTypeOfType: getIndexTypeOfType,
|
||||
getReturnTypeOfSignature: getReturnTypeOfSignature,
|
||||
getSymbolsInScope: getSymbolsInScope,
|
||||
getSymbolInfo: getSymbolInfo,
|
||||
getTypeOfNode: getTypeOfNode,
|
||||
typeToString: typeToString,
|
||||
getSymbolDisplayBuilder: getSymbolDisplayBuilder,
|
||||
symbolToString: symbolToString,
|
||||
getAugmentedPropertiesOfType: getAugmentedPropertiesOfType,
|
||||
getRootSymbols: getRootSymbols,
|
||||
getContextualType: getContextualType,
|
||||
getFullyQualifiedName: getFullyQualifiedName,
|
||||
getResolvedSignature: getResolvedSignature,
|
||||
getEnumMemberValue: getEnumMemberValue,
|
||||
isValidPropertyAccess: isValidPropertyAccess,
|
||||
getSignatureFromDeclaration: getSignatureFromDeclaration,
|
||||
isImplementationOfOverload: isImplementationOfOverload,
|
||||
getAliasedSymbol: resolveImport,
|
||||
isUndefinedSymbol: symbol => symbol === undefinedSymbol,
|
||||
isArgumentsSymbol: symbol => symbol === argumentsSymbol,
|
||||
hasEarlyErrors: hasEarlyErrors
|
||||
getDiagnostics,
|
||||
getGlobalDiagnostics,
|
||||
checkProgram,
|
||||
invokeEmitter,
|
||||
getParentOfSymbol,
|
||||
getNarrowedTypeOfSymbol,
|
||||
getDeclaredTypeOfSymbol,
|
||||
getPropertiesOfType,
|
||||
getPropertyOfType,
|
||||
getSignaturesOfType,
|
||||
getIndexTypeOfType,
|
||||
getReturnTypeOfSignature,
|
||||
getSymbolsInScope,
|
||||
getSymbolInfo,
|
||||
getShorthandAssignmentValueSymbol,
|
||||
getTypeOfNode,
|
||||
typeToString,
|
||||
getSymbolDisplayBuilder,
|
||||
symbolToString,
|
||||
getAugmentedPropertiesOfType,
|
||||
getRootSymbols,
|
||||
getContextualType,
|
||||
getFullyQualifiedName,
|
||||
getResolvedSignature,
|
||||
getEnumMemberValue,
|
||||
isValidPropertyAccess,
|
||||
getSignatureFromDeclaration,
|
||||
isImplementationOfOverload,
|
||||
getAliasedSymbol: resolveImport,
|
||||
hasEarlyErrors,
|
||||
isEmitBlocked,
|
||||
};
|
||||
|
||||
var undefinedSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "undefined");
|
||||
@@ -951,7 +953,7 @@ module ts {
|
||||
if (forEach(symbol.declarations, declaration => !getIsDeclarationVisible(declaration))) {
|
||||
return undefined;
|
||||
}
|
||||
return { aliasesToMakeVisible: aliasesToMakeVisible };
|
||||
return { aliasesToMakeVisible };
|
||||
|
||||
function getIsDeclarationVisible(declaration: Declaration) {
|
||||
if (!isDeclarationVisible(declaration)) {
|
||||
@@ -1665,6 +1667,13 @@ module ts {
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
// If it is a short-hand property assignment; Use the type of the identifier
|
||||
if (declaration.kind === SyntaxKind.ShorthandPropertyAssignment) {
|
||||
var type = checkIdentifier(<Identifier>declaration.name);
|
||||
return type
|
||||
}
|
||||
|
||||
// Rest parameters default to type any[], other parameters default to type any
|
||||
var type = declaration.flags & NodeFlags.Rest ? createArrayType(anyType) : anyType;
|
||||
checkImplicitAny(type);
|
||||
@@ -2399,7 +2408,7 @@ module ts {
|
||||
}
|
||||
|
||||
// Return the symbol for the property with the given name in the given type. Creates synthetic union properties when
|
||||
// necessary, maps primtive types and type parameters are to their apparent types, and augments with properties from
|
||||
// necessary, maps primitive types and type parameters are to their apparent types, and augments with properties from
|
||||
// Object and Function as appropriate.
|
||||
function getPropertyOfType(type: Type, name: string): Symbol {
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
@@ -2434,7 +2443,7 @@ module ts {
|
||||
}
|
||||
|
||||
// Return the signatures of the given kind in the given type. Creates synthetic union signatures when necessary and
|
||||
// maps primtive types and type parameters are to their apparent types.
|
||||
// maps primitive types and type parameters are to their apparent types.
|
||||
function getSignaturesOfType(type: Type, kind: SignatureKind): Signature[] {
|
||||
return getSignaturesOfObjectOrUnionType(getApparentType(type), kind);
|
||||
}
|
||||
@@ -2447,7 +2456,7 @@ module ts {
|
||||
}
|
||||
|
||||
// Return the index type of the given kind in the given type. Creates synthetic union index types when necessary and
|
||||
// maps primtive types and type parameters are to their apparent types.
|
||||
// maps primitive types and type parameters are to their apparent types.
|
||||
function getIndexTypeOfType(type: Type, kind: IndexKind): Type {
|
||||
return getIndexTypeOfObjectOrUnionType(getApparentType(type), kind);
|
||||
}
|
||||
@@ -2523,6 +2532,8 @@ module ts {
|
||||
for (var i = 0, len = symbol.declarations.length; i < len; i++) {
|
||||
var node = symbol.declarations[i];
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.Constructor:
|
||||
@@ -2960,8 +2971,8 @@ module ts {
|
||||
}
|
||||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function getTypeFromTypeLiteralNode(node: TypeLiteralNode): Type {
|
||||
|
||||
function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: Node): Type {
|
||||
var links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
// Deferred resolution of members is handled by resolveObjectTypeMembers
|
||||
@@ -3011,8 +3022,10 @@ module ts {
|
||||
return getTypeFromUnionTypeNode(<UnionTypeNode>node);
|
||||
case SyntaxKind.ParenType:
|
||||
return getTypeFromTypeNode((<ParenTypeNode>node).type);
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.TypeLiteral:
|
||||
return getTypeFromTypeLiteralNode(<TypeLiteralNode>node);
|
||||
return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node);
|
||||
// This function assumes that an identifier or qualified name is a type expression
|
||||
// Callers should first ensure this by calling isTypeNode
|
||||
case SyntaxKind.Identifier:
|
||||
@@ -3221,9 +3234,9 @@ module ts {
|
||||
|
||||
// TYPE CHECKING
|
||||
|
||||
var subtypeRelation: Map<Ternary> = {};
|
||||
var assignableRelation: Map<Ternary> = {};
|
||||
var identityRelation: Map<Ternary> = {};
|
||||
var subtypeRelation: Map<boolean> = {};
|
||||
var assignableRelation: Map<boolean> = {};
|
||||
var identityRelation: Map<boolean> = {};
|
||||
|
||||
function isTypeIdenticalTo(source: Type, target: Type): boolean {
|
||||
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined);
|
||||
@@ -3258,7 +3271,7 @@ module ts {
|
||||
function checkTypeRelatedTo(
|
||||
source: Type,
|
||||
target: Type,
|
||||
relation: Map<Ternary>,
|
||||
relation: Map<boolean>,
|
||||
errorNode: Node,
|
||||
headMessage?: DiagnosticMessage,
|
||||
containingMessageChain?: DiagnosticMessageChain): boolean {
|
||||
@@ -3266,6 +3279,7 @@ module ts {
|
||||
var errorInfo: DiagnosticMessageChain;
|
||||
var sourceStack: ObjectType[];
|
||||
var targetStack: ObjectType[];
|
||||
var maybeStack: Map<boolean>[];
|
||||
var expandingFlags: number;
|
||||
var depth = 0;
|
||||
var overflow = false;
|
||||
@@ -3424,12 +3438,12 @@ module ts {
|
||||
var id = source.id + "," + target.id;
|
||||
var related = relation[id];
|
||||
if (related !== undefined) {
|
||||
return related;
|
||||
return related ? Ternary.True : Ternary.False;
|
||||
}
|
||||
if (depth > 0) {
|
||||
for (var i = 0; i < depth; i++) {
|
||||
// If source and target are already being compared, consider them related with assumptions
|
||||
if (source === sourceStack[i] && target === targetStack[i]) {
|
||||
if (maybeStack[i][id]) {
|
||||
return Ternary.Maybe;
|
||||
}
|
||||
}
|
||||
@@ -3441,16 +3455,19 @@ module ts {
|
||||
else {
|
||||
sourceStack = [];
|
||||
targetStack = [];
|
||||
maybeStack = [];
|
||||
expandingFlags = 0;
|
||||
}
|
||||
sourceStack[depth] = source;
|
||||
targetStack[depth] = target;
|
||||
maybeStack[depth] = {};
|
||||
maybeStack[depth][id] = true;
|
||||
depth++;
|
||||
var saveExpandingFlags = expandingFlags;
|
||||
if (!(expandingFlags & 1) && isDeeplyNestedGeneric(source, sourceStack)) expandingFlags |= 1;
|
||||
if (!(expandingFlags & 2) && isDeeplyNestedGeneric(target, targetStack)) expandingFlags |= 2;
|
||||
if (expandingFlags === 3) {
|
||||
var result = Ternary.True;
|
||||
var result = Ternary.Maybe;
|
||||
}
|
||||
else {
|
||||
var result = propertiesRelatedTo(source, target, reportErrors);
|
||||
@@ -3469,9 +3486,18 @@ module ts {
|
||||
}
|
||||
expandingFlags = saveExpandingFlags;
|
||||
depth--;
|
||||
// Only cache results that are free of assumptions
|
||||
if (result !== Ternary.Maybe) {
|
||||
relation[id] = result;
|
||||
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];
|
||||
for (var p in maybeCache) {
|
||||
destinationCache[p] = maybeCache[p];
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -4319,13 +4345,9 @@ module ts {
|
||||
var type = getTypeOfSymbol(symbol);
|
||||
// Only narrow when symbol is variable of a structured type
|
||||
if (node && (symbol.flags & SymbolFlags.Variable && type.flags & TypeFlags.Structured)) {
|
||||
while (true) {
|
||||
loop: while (true) {
|
||||
var child = node;
|
||||
node = node.parent;
|
||||
// Stop at containing function or module block
|
||||
if (!node || node.kind === SyntaxKind.FunctionBlock || node.kind === SyntaxKind.ModuleBlock) {
|
||||
break;
|
||||
}
|
||||
var narrowedType = type;
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.IfStatement:
|
||||
@@ -4351,9 +4373,18 @@ module ts {
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.SourceFile:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.Constructor:
|
||||
// Stop at the first containing function or module declaration
|
||||
break loop;
|
||||
}
|
||||
// Only use narrowed type if construct contains no assignments to variable
|
||||
if (narrowedType !== type) {
|
||||
// Use narrowed type if it is a subtype and construct contains no assignments to variable
|
||||
if (narrowedType !== type && isTypeSubtypeOf(narrowedType, type)) {
|
||||
if (isVariableAssignedWithin(symbol, node)) {
|
||||
break;
|
||||
}
|
||||
@@ -4474,7 +4505,7 @@ module ts {
|
||||
if (symbol.flags & SymbolFlags.Import) {
|
||||
// Mark the import as referenced so that we emit it in the final .js file.
|
||||
// exception: identifiers that appear in type queries, const enums, modules that contain only const enums
|
||||
getSymbolLinks(symbol).referenced = !isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(resolveImport(symbol));
|
||||
getSymbolLinks(symbol).referenced = getSymbolLinks(symbol).referenced || (!isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(resolveImport(symbol)));
|
||||
}
|
||||
|
||||
checkCollisionWithCapturedSuperVariable(node, node);
|
||||
@@ -4991,7 +5022,15 @@ module ts {
|
||||
if (hasProperty(members, id)) {
|
||||
var member = members[id];
|
||||
if (member.flags & SymbolFlags.Property) {
|
||||
var type = checkExpression((<PropertyDeclaration>member.declarations[0]).initializer, contextualMapper);
|
||||
var memberDecl = <PropertyDeclaration>member.declarations[0];
|
||||
var type: Type;
|
||||
if (memberDecl.kind === SyntaxKind.PropertyAssignment) {
|
||||
type = checkExpression(memberDecl.initializer, contextualMapper);
|
||||
}
|
||||
else {
|
||||
Debug.assert(memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment);
|
||||
type = checkExpression(memberDecl.name, contextualMapper);
|
||||
}
|
||||
var prop = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | member.flags, member.name);
|
||||
prop.declarations = member.declarations;
|
||||
prop.parent = member.parent;
|
||||
@@ -5394,7 +5433,7 @@ module ts {
|
||||
return typeArgumentsAreAssignable;
|
||||
}
|
||||
|
||||
function checkApplicableSignature(node: CallLikeExpression, args: Node[], signature: Signature, relation: Map<Ternary>, excludeArgument: boolean[], reportErrors: boolean) {
|
||||
function checkApplicableSignature(node: CallLikeExpression, args: Node[], signature: Signature, relation: Map<boolean>, excludeArgument: boolean[], reportErrors: boolean) {
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
var arg = args[i];
|
||||
var argType: Type;
|
||||
@@ -5588,7 +5627,7 @@ module ts {
|
||||
|
||||
return resolveErrorCall(node);
|
||||
|
||||
function chooseOverload(candidates: Signature[], relation: Map<Ternary>) {
|
||||
function chooseOverload(candidates: Signature[], relation: Map<boolean>) {
|
||||
for (var i = 0; i < candidates.length; i++) {
|
||||
if (!hasCorrectArity(node, args, candidates[i])) {
|
||||
continue;
|
||||
@@ -5853,7 +5892,11 @@ module ts {
|
||||
}
|
||||
if (node.kind === SyntaxKind.NewExpression) {
|
||||
var declaration = signature.declaration;
|
||||
if (declaration && (declaration.kind !== SyntaxKind.Constructor && declaration.kind !== SyntaxKind.ConstructSignature)) {
|
||||
if (declaration &&
|
||||
declaration.kind !== SyntaxKind.Constructor &&
|
||||
declaration.kind !== SyntaxKind.ConstructSignature &&
|
||||
declaration.kind !== SyntaxKind.ConstructorType) {
|
||||
|
||||
// When resolved signature is a call signature (and not a construct signature) the result type is any
|
||||
if (compilerOptions.noImplicitAny) {
|
||||
error(node, Diagnostics.new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type);
|
||||
@@ -6796,7 +6839,7 @@ module ts {
|
||||
function checkTypeLiteral(node: TypeLiteralNode) {
|
||||
forEach(node.members, checkSourceElement);
|
||||
if (fullTypeCheck) {
|
||||
var type = getTypeFromTypeLiteralNode(node);
|
||||
var type = getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node);
|
||||
checkIndexConstraints(type);
|
||||
checkTypeForDuplicateIndexSignatures(node);
|
||||
}
|
||||
@@ -8270,6 +8313,8 @@ module ts {
|
||||
return checkParameter(<ParameterDeclaration>node);
|
||||
case SyntaxKind.Property:
|
||||
return checkPropertyDeclaration(<PropertyDeclaration>node);
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.IndexSignature:
|
||||
@@ -8801,6 +8846,16 @@ module ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getShorthandAssignmentValueSymbol(location: Node): Symbol {
|
||||
// The function returns a value symbol of an identifier in the short-hand property assignment.
|
||||
// This is necessary as an identifier in short-hand property assignment can contains two meaning:
|
||||
// property name and property value.
|
||||
if (location && location.kind === SyntaxKind.ShorthandPropertyAssignment) {
|
||||
return resolveEntityName(location, (<ShortHandPropertyDeclaration>location).name, SymbolFlags.Value);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getTypeOfNode(node: Node): Type {
|
||||
if (isInsideWithStatementBody(node)) {
|
||||
// We cannot answer semantic questions within a with block, do not proceed any further
|
||||
@@ -8969,6 +9024,12 @@ module ts {
|
||||
return getDiagnostics().length > 0 || getGlobalDiagnostics().length > 0;
|
||||
}
|
||||
|
||||
function isEmitBlocked(sourceFile?: SourceFile): boolean {
|
||||
return program.getDiagnostics(sourceFile).length !== 0 ||
|
||||
hasEarlyErrors(sourceFile) ||
|
||||
(compilerOptions.noEmitOnError && getDiagnostics(sourceFile).length !== 0);
|
||||
}
|
||||
|
||||
function hasEarlyErrors(sourceFile?: SourceFile): boolean {
|
||||
return forEach(getDiagnostics(sourceFile), d => d.isEarly);
|
||||
}
|
||||
@@ -9042,7 +9103,9 @@ module ts {
|
||||
function writeTypeAtLocation(location: Node, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter) {
|
||||
// Get type of the symbol if this is the valid symbol otherwise get type at location
|
||||
var symbol = getSymbolOfNode(location);
|
||||
var type = symbol && !(symbol.flags & SymbolFlags.TypeLiteral) ? getTypeOfSymbol(symbol) : getTypeFromTypeNode(location);
|
||||
var type = symbol && !(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.CallSignature | SymbolFlags.ConstructSignature))
|
||||
? getTypeOfSymbol(symbol)
|
||||
: getTypeFromTypeNode(location);
|
||||
|
||||
getSymbolDisplayBuilder().buildTypeDisplay(type, writer, enclosingDeclaration, flags);
|
||||
}
|
||||
@@ -9055,22 +9118,22 @@ module ts {
|
||||
function invokeEmitter(targetSourceFile?: SourceFile) {
|
||||
var resolver: EmitResolver = {
|
||||
getProgram: () => program,
|
||||
getLocalNameOfContainer: getLocalNameOfContainer,
|
||||
getExpressionNamePrefix: getExpressionNamePrefix,
|
||||
getExportAssignmentName: getExportAssignmentName,
|
||||
isReferencedImportDeclaration: isReferencedImportDeclaration,
|
||||
getNodeCheckFlags: getNodeCheckFlags,
|
||||
getEnumMemberValue: getEnumMemberValue,
|
||||
isTopLevelValueImportWithEntityName: isTopLevelValueImportWithEntityName,
|
||||
hasSemanticErrors: hasSemanticErrors,
|
||||
hasEarlyErrors: hasEarlyErrors,
|
||||
isDeclarationVisible: isDeclarationVisible,
|
||||
isImplementationOfOverload: isImplementationOfOverload,
|
||||
writeTypeAtLocation: writeTypeAtLocation,
|
||||
writeReturnTypeOfSignatureDeclaration: writeReturnTypeOfSignatureDeclaration,
|
||||
isSymbolAccessible: isSymbolAccessible,
|
||||
isImportDeclarationEntityNameReferenceDeclarationVisibile: isImportDeclarationEntityNameReferenceDeclarationVisibile,
|
||||
getConstantValue: getConstantValue,
|
||||
getLocalNameOfContainer,
|
||||
getExpressionNamePrefix,
|
||||
getExportAssignmentName,
|
||||
isReferencedImportDeclaration,
|
||||
getNodeCheckFlags,
|
||||
getEnumMemberValue,
|
||||
isTopLevelValueImportWithEntityName,
|
||||
hasSemanticErrors,
|
||||
isEmitBlocked,
|
||||
isDeclarationVisible,
|
||||
isImplementationOfOverload,
|
||||
writeTypeAtLocation,
|
||||
writeReturnTypeOfSignatureDeclaration,
|
||||
isSymbolAccessible,
|
||||
isImportDeclarationEntityNameReferenceDeclarationVisibile,
|
||||
getConstantValue,
|
||||
};
|
||||
checkProgram();
|
||||
return emitFiles(resolver, targetSourceFile);
|
||||
@@ -9102,7 +9165,12 @@ module ts {
|
||||
globalNumberType = getGlobalType("Number");
|
||||
globalBooleanType = getGlobalType("Boolean");
|
||||
globalRegExpType = getGlobalType("RegExp");
|
||||
globalTemplateStringsArrayType = getGlobalType("TemplateStringsArray");
|
||||
|
||||
// If we're in ES6 mode, load the TemplateStringsArray.
|
||||
// Otherwise, default to 'unknown' for the purposes of type checking in LS scenarios.
|
||||
globalTemplateStringsArrayType = compilerOptions.target >= ScriptTarget.ES6
|
||||
? getGlobalType("TemplateStringsArray")
|
||||
: unknownType;
|
||||
}
|
||||
|
||||
initializeTypeChecker();
|
||||
|
||||
@@ -54,6 +54,11 @@ module ts {
|
||||
paramType: Diagnostics.KIND,
|
||||
error: Diagnostics.Argument_for_module_option_must_be_commonjs_or_amd
|
||||
},
|
||||
{
|
||||
name: "noEmitOnError",
|
||||
type: "boolean",
|
||||
description: Diagnostics.Do_not_emit_outputs_if_any_type_checking_errors_were_reported,
|
||||
},
|
||||
{
|
||||
name: "noImplicitAny",
|
||||
type: "boolean",
|
||||
@@ -148,9 +153,9 @@ module ts {
|
||||
|
||||
parseStrings(commandLine);
|
||||
return {
|
||||
options: options,
|
||||
filenames: filenames,
|
||||
errors: errors
|
||||
options,
|
||||
filenames,
|
||||
errors
|
||||
};
|
||||
|
||||
function parseStrings(args: string[]) {
|
||||
|
||||
@@ -258,9 +258,9 @@ module ts {
|
||||
}
|
||||
|
||||
return {
|
||||
file: file,
|
||||
start: start,
|
||||
length: length,
|
||||
file,
|
||||
start,
|
||||
length,
|
||||
|
||||
messageText: text,
|
||||
category: message.category,
|
||||
@@ -335,12 +335,12 @@ module ts {
|
||||
}
|
||||
|
||||
return {
|
||||
file: file,
|
||||
start: start,
|
||||
length: length,
|
||||
code: code,
|
||||
category: category,
|
||||
messageText: messageText
|
||||
file,
|
||||
start,
|
||||
length,
|
||||
code,
|
||||
category,
|
||||
messageText
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -122,6 +122,9 @@ module ts {
|
||||
let_declarations_can_only_be_declared_inside_a_block: { code: 1157, category: DiagnosticCategory.Error, key: "'let' declarations can only be declared inside a block." },
|
||||
Invalid_template_literal_expected: { code: 1158, category: DiagnosticCategory.Error, key: "Invalid template literal; expected '}'" },
|
||||
Tagged_templates_are_only_available_when_targeting_ECMAScript_6_and_higher: { code: 1159, category: DiagnosticCategory.Error, key: "Tagged templates are only available when targeting ECMAScript 6 and higher." },
|
||||
Unterminated_template_literal: { code: 1160, category: DiagnosticCategory.Error, key: "Unterminated template literal." },
|
||||
Unterminated_regular_expression_literal: { code: 1161, category: DiagnosticCategory.Error, key: "Unterminated regular expression literal." },
|
||||
A_object_member_cannot_be_declared_optional: { code: 1160, category: DiagnosticCategory.Error, key: "A object member cannot be declared optional." },
|
||||
Duplicate_identifier_0: { code: 2300, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'." },
|
||||
Initializer_of_instance_member_variable_0_cannot_reference_identifier_1_declared_in_the_constructor: { code: 2301, category: DiagnosticCategory.Error, key: "Initializer of instance member variable '{0}' cannot reference identifier '{1}' declared in the constructor." },
|
||||
Static_members_cannot_reference_class_type_parameters: { code: 2302, category: DiagnosticCategory.Error, key: "Static members cannot reference class type parameters." },
|
||||
@@ -270,6 +273,7 @@ module ts {
|
||||
Type_argument_candidate_1_is_not_a_valid_type_argument_because_it_is_not_a_supertype_of_candidate_0: { code: 2455, category: DiagnosticCategory.Error, key: "Type argument candidate '{1}' is not a valid type argument because it is not a supertype of candidate '{0}'." },
|
||||
Type_alias_0_circularly_references_itself: { code: 2456, category: DiagnosticCategory.Error, key: "Type alias '{0}' circularly references itself." },
|
||||
Type_alias_name_cannot_be_0: { code: 2457, category: DiagnosticCategory.Error, key: "Type alias name cannot be '{0}'" },
|
||||
An_AMD_module_cannot_have_multiple_name_assignments: { code: 2458, category: DiagnosticCategory.Error, key: "An AMD module cannot have multiple name assignments." },
|
||||
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_name_1_from_private_module_2: { code: 4001, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using name '{1}' from private module '{2}'." },
|
||||
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}'." },
|
||||
@@ -373,6 +377,7 @@ module ts {
|
||||
Watch_input_files: { code: 6005, category: DiagnosticCategory.Message, key: "Watch input files." },
|
||||
Redirect_output_structure_to_the_directory: { code: 6006, category: DiagnosticCategory.Message, key: "Redirect output structure to the directory." },
|
||||
Do_not_erase_const_enum_declarations_in_generated_code: { code: 6007, category: DiagnosticCategory.Message, key: "Do not erase const enum declarations in generated code." },
|
||||
Do_not_emit_outputs_if_any_type_checking_errors_were_reported: { code: 6008, category: DiagnosticCategory.Message, key: "Do not emit outputs if any type checking errors were reported." },
|
||||
Do_not_emit_comments_to_output: { code: 6009, category: DiagnosticCategory.Message, key: "Do not emit comments to output." },
|
||||
Specify_ECMAScript_target_version_Colon_ES3_default_ES5_or_ES6_experimental: { code: 6015, category: DiagnosticCategory.Message, key: "Specify ECMAScript target version: 'ES3' (default), 'ES5', or 'ES6' (experimental)" },
|
||||
Specify_module_code_generation_Colon_commonjs_or_amd: { code: 6016, category: DiagnosticCategory.Message, key: "Specify module code generation: 'commonjs' or 'amd'" },
|
||||
|
||||
@@ -479,6 +479,19 @@
|
||||
"category": "Error",
|
||||
"code": 1159
|
||||
},
|
||||
"Unterminated template literal.": {
|
||||
"category": "Error",
|
||||
"code": 1160
|
||||
},
|
||||
"Unterminated regular expression literal.": {
|
||||
"category": "Error",
|
||||
"code": 1161
|
||||
},
|
||||
|
||||
"A object member cannot be declared optional.": {
|
||||
"category": "Error",
|
||||
"code": 1160
|
||||
},
|
||||
|
||||
"Duplicate identifier '{0}'.": {
|
||||
"category": "Error",
|
||||
@@ -1076,6 +1089,10 @@
|
||||
"category": "Error",
|
||||
"code": 2457
|
||||
},
|
||||
"An AMD module cannot have multiple name assignments.": {
|
||||
"category": "Error",
|
||||
"code": 2458
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
@@ -1490,6 +1507,10 @@
|
||||
"category": "Message",
|
||||
"code": 6007
|
||||
},
|
||||
"Do not emit outputs if any type checking errors were reported.": {
|
||||
"category": "Message",
|
||||
"code": 6008
|
||||
},
|
||||
"Do not emit comments to output.": {
|
||||
"category": "Message",
|
||||
"code": 6009
|
||||
|
||||
+75
-31
@@ -104,9 +104,9 @@ module ts {
|
||||
}
|
||||
});
|
||||
return {
|
||||
firstAccessor: firstAccessor,
|
||||
getAccessor: getAccessor,
|
||||
setAccessor: setAccessor
|
||||
firstAccessor,
|
||||
getAccessor,
|
||||
setAccessor
|
||||
};
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ module ts {
|
||||
function writeLiteral(s: string) {
|
||||
if (s && s.length) {
|
||||
write(s);
|
||||
var lineStartsOfS = getLineStarts(s);
|
||||
var lineStartsOfS = computeLineStarts(s);
|
||||
if (lineStartsOfS.length > 1) {
|
||||
lineCount = lineCount + lineStartsOfS.length - 1;
|
||||
linePos = output.length - s.length + lineStartsOfS[lineStartsOfS.length - 1];
|
||||
@@ -927,13 +927,14 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function isNonExpressionIdentifier(node: Identifier) {
|
||||
function isNotExpressionIdentifier(node: Identifier) {
|
||||
var parent = node.parent;
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.Property:
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
case SyntaxKind.EnumMember:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
@@ -957,17 +958,24 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function emitIdentifier(node: Identifier) {
|
||||
if (!isNonExpressionIdentifier(node)) {
|
||||
var prefix = resolver.getExpressionNamePrefix(node);
|
||||
if (prefix) {
|
||||
write(prefix);
|
||||
write(".");
|
||||
}
|
||||
function emitExpressionIdentifier(node: Identifier) {
|
||||
var prefix = resolver.getExpressionNamePrefix(node);
|
||||
if (prefix) {
|
||||
write(prefix);
|
||||
write(".");
|
||||
}
|
||||
write(getSourceTextOfLocalNode(node));
|
||||
}
|
||||
|
||||
function emitIdentifier(node: Identifier) {
|
||||
if (!isNotExpressionIdentifier(node)) {
|
||||
emitExpressionIdentifier(node);
|
||||
}
|
||||
else {
|
||||
write(getSourceTextOfLocalNode(node));
|
||||
}
|
||||
}
|
||||
|
||||
function emitThis(node: Node) {
|
||||
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.LexicalThis) {
|
||||
write("_this");
|
||||
@@ -1033,6 +1041,36 @@ module ts {
|
||||
emitTrailingComments(node);
|
||||
}
|
||||
|
||||
function emitShortHandPropertyAssignment(node: ShortHandPropertyDeclaration) {
|
||||
function emitAsNormalPropertyAssignment() {
|
||||
emitLeadingComments(node);
|
||||
// Emit identifier as an identifier
|
||||
emit(node.name);
|
||||
write(": ");
|
||||
// Even though this is stored as identified because it is in short-hand property assignment,
|
||||
// treated it as expression
|
||||
emitExpressionIdentifier(node.name);
|
||||
emitTrailingComments(node);
|
||||
}
|
||||
|
||||
if (compilerOptions.target < ScriptTarget.ES6) {
|
||||
emitAsNormalPropertyAssignment();
|
||||
}
|
||||
else if (compilerOptions.target >= ScriptTarget.ES6) {
|
||||
// If short-hand property has a prefix, then regardless of the target version, we will emit it as normal property assignment
|
||||
var prefix = resolver.getExpressionNamePrefix(node.name);
|
||||
if (prefix) {
|
||||
emitAsNormalPropertyAssignment();
|
||||
}
|
||||
// If short-hand property has no prefix, emit it as short-hand.
|
||||
else {
|
||||
emitLeadingComments(node);
|
||||
emit(node.name);
|
||||
emitTrailingComments(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tryEmitConstantValue(node: PropertyAccess | IndexedAccess): boolean {
|
||||
var constantValue = resolver.getConstantValue(node);
|
||||
if (constantValue !== undefined) {
|
||||
@@ -2096,7 +2134,11 @@ module ts {
|
||||
function emitAMDModule(node: SourceFile, startIndex: number) {
|
||||
var imports = getExternalImportDeclarations(node);
|
||||
writeLine();
|
||||
write("define([\"require\", \"exports\"");
|
||||
write("define(");
|
||||
if(node.amdModuleName) {
|
||||
write("\"" + node.amdModuleName + "\", ");
|
||||
}
|
||||
write("[\"require\", \"exports\"");
|
||||
forEach(imports, imp => {
|
||||
write(", ");
|
||||
emitLiteral(imp.externalModuleName);
|
||||
@@ -2250,6 +2292,8 @@ module ts {
|
||||
return emitObjectLiteral(<ObjectLiteral>node);
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
return emitPropertyAssignment(<PropertyDeclaration>node);
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
return emitShortHandPropertyAssignment(<ShortHandPropertyDeclaration>node);
|
||||
case SyntaxKind.PropertyAccess:
|
||||
return emitPropertyAccess(<PropertyAccess>node);
|
||||
case SyntaxKind.IndexedAccess:
|
||||
@@ -2743,7 +2787,7 @@ module ts {
|
||||
Diagnostics.Exported_type_alias_0_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1;
|
||||
return {
|
||||
diagnosticMessage: diagnosticMessage,
|
||||
diagnosticMessage,
|
||||
errorNode: node,
|
||||
typeName: node.name
|
||||
};
|
||||
@@ -2840,7 +2884,7 @@ module ts {
|
||||
}
|
||||
|
||||
return {
|
||||
diagnosticMessage: diagnosticMessage,
|
||||
diagnosticMessage,
|
||||
errorNode: node,
|
||||
typeName: node.name
|
||||
};
|
||||
@@ -2905,7 +2949,7 @@ module ts {
|
||||
}
|
||||
|
||||
return {
|
||||
diagnosticMessage: diagnosticMessage,
|
||||
diagnosticMessage,
|
||||
errorNode: node,
|
||||
typeName: (<Declaration>node.parent).name
|
||||
};
|
||||
@@ -3087,7 +3131,7 @@ module ts {
|
||||
Diagnostics.Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
return {
|
||||
diagnosticMessage: diagnosticMessage,
|
||||
diagnosticMessage,
|
||||
errorNode: <Node>node.parameters[0],
|
||||
// TODO(jfreeman): Investigate why we are passing node.name instead of node.parameters[0].name
|
||||
typeName: node.name
|
||||
@@ -3109,7 +3153,7 @@ module ts {
|
||||
Diagnostics.Return_type_of_public_property_getter_from_exported_class_has_or_is_using_private_name_0;
|
||||
}
|
||||
return {
|
||||
diagnosticMessage: diagnosticMessage,
|
||||
diagnosticMessage,
|
||||
errorNode: <Node>node.name,
|
||||
typeName: undefined
|
||||
};
|
||||
@@ -3239,7 +3283,7 @@ module ts {
|
||||
}
|
||||
|
||||
return {
|
||||
diagnosticMessage: diagnosticMessage,
|
||||
diagnosticMessage,
|
||||
errorNode: <Node>node.name || node,
|
||||
};
|
||||
}
|
||||
@@ -3324,7 +3368,7 @@ module ts {
|
||||
}
|
||||
|
||||
return {
|
||||
diagnosticMessage: diagnosticMessage,
|
||||
diagnosticMessage,
|
||||
errorNode: node,
|
||||
typeName: node.name
|
||||
};
|
||||
@@ -3458,10 +3502,10 @@ module ts {
|
||||
}
|
||||
|
||||
var hasSemanticErrors = resolver.hasSemanticErrors();
|
||||
var hasEarlyErrors = resolver.hasEarlyErrors(targetSourceFile);
|
||||
var isEmitBlocked = resolver.isEmitBlocked(targetSourceFile);
|
||||
|
||||
function emitFile(jsFilePath: string, sourceFile?: SourceFile) {
|
||||
if (!hasEarlyErrors) {
|
||||
if (!isEmitBlocked) {
|
||||
emitJavaScript(jsFilePath, sourceFile);
|
||||
if (!hasSemanticErrors && compilerOptions.declaration) {
|
||||
emitDeclarations(jsFilePath, sourceFile);
|
||||
@@ -3504,22 +3548,22 @@ module ts {
|
||||
var hasEmitterError = forEach(diagnostics, diagnostic => diagnostic.category === DiagnosticCategory.Error);
|
||||
|
||||
// Check and update returnCode for syntactic and semantic
|
||||
var returnCode: EmitReturnStatus;
|
||||
if (hasEarlyErrors) {
|
||||
returnCode = EmitReturnStatus.AllOutputGenerationSkipped;
|
||||
var emitResultStatus: EmitReturnStatus;
|
||||
if (isEmitBlocked) {
|
||||
emitResultStatus = EmitReturnStatus.AllOutputGenerationSkipped;
|
||||
} else if (hasEmitterError) {
|
||||
returnCode = EmitReturnStatus.EmitErrorsEncountered;
|
||||
emitResultStatus = EmitReturnStatus.EmitErrorsEncountered;
|
||||
} else if (hasSemanticErrors && compilerOptions.declaration) {
|
||||
returnCode = EmitReturnStatus.DeclarationGenerationSkipped;
|
||||
emitResultStatus = EmitReturnStatus.DeclarationGenerationSkipped;
|
||||
} else if (hasSemanticErrors && !compilerOptions.declaration) {
|
||||
returnCode = EmitReturnStatus.JSGeneratedWithSemanticErrors;
|
||||
emitResultStatus = EmitReturnStatus.JSGeneratedWithSemanticErrors;
|
||||
} else {
|
||||
returnCode = EmitReturnStatus.Succeeded;
|
||||
emitResultStatus = EmitReturnStatus.Succeeded;
|
||||
}
|
||||
|
||||
return {
|
||||
emitResultStatus: returnCode,
|
||||
errors: diagnostics,
|
||||
emitResultStatus,
|
||||
diagnostics,
|
||||
sourceMaps: sourceMapDataList
|
||||
};
|
||||
}
|
||||
|
||||
+83
-40
@@ -20,6 +20,7 @@ module ts {
|
||||
interface ReferenceComments {
|
||||
referencedFiles: FileReference[];
|
||||
amdDependencies: string[];
|
||||
amdModuleName: string;
|
||||
}
|
||||
|
||||
export function getSourceFileOfNode(node: Node): SourceFile {
|
||||
@@ -34,12 +35,16 @@ module ts {
|
||||
return file.filename + "(" + loc.line + "," + loc.character + ")";
|
||||
}
|
||||
|
||||
|
||||
export function getStartPosOfNode(node: Node): number {
|
||||
return node.pos;
|
||||
}
|
||||
|
||||
export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile): number {
|
||||
// With nodes that have no width (i.e. 'Missing' nodes), we actually *don't*
|
||||
// want to skip trivia because this will launch us forward to the next token.
|
||||
if (node.pos === node.end) {
|
||||
return node.pos;
|
||||
}
|
||||
return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos);
|
||||
}
|
||||
|
||||
@@ -198,9 +203,12 @@ module ts {
|
||||
child((<ParameterDeclaration>node).initializer);
|
||||
case SyntaxKind.Property:
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
return child((<PropertyDeclaration>node).name) ||
|
||||
child((<PropertyDeclaration>node).type) ||
|
||||
child((<PropertyDeclaration>node).initializer);
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.IndexSignature:
|
||||
@@ -574,6 +582,7 @@ module ts {
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.Property:
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
case SyntaxKind.EnumMember:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
@@ -774,13 +783,12 @@ module ts {
|
||||
if (matchResult) {
|
||||
var start = commentRange.pos;
|
||||
var end = commentRange.end;
|
||||
var fileRef = {
|
||||
pos: start,
|
||||
end: end,
|
||||
filename: matchResult[3]
|
||||
};
|
||||
return {
|
||||
fileReference: fileRef,
|
||||
fileReference: {
|
||||
pos: start,
|
||||
end: end,
|
||||
filename: matchResult[3]
|
||||
},
|
||||
isNoDefaultLib: false
|
||||
};
|
||||
}
|
||||
@@ -944,26 +952,24 @@ module ts {
|
||||
}
|
||||
|
||||
return {
|
||||
addLabel: addLabel,
|
||||
pushCurrentLabelSet: pushCurrentLabelSet,
|
||||
pushFunctionBoundary: pushFunctionBoundary,
|
||||
pop: pop,
|
||||
nodeIsNestedInLabel: nodeIsNestedInLabel,
|
||||
addLabel,
|
||||
pushCurrentLabelSet,
|
||||
pushFunctionBoundary,
|
||||
pop,
|
||||
nodeIsNestedInLabel,
|
||||
};
|
||||
})();
|
||||
|
||||
function getLineAndCharacterlFromSourcePosition(position: number) {
|
||||
if (!lineStarts) {
|
||||
lineStarts = getLineStarts(sourceText);
|
||||
}
|
||||
return getLineAndCharacterOfPosition(lineStarts, position);
|
||||
function getLineStarts(): number[] {
|
||||
return lineStarts || (lineStarts = computeLineStarts(sourceText));
|
||||
}
|
||||
|
||||
function getLineAndCharacterFromSourcePosition(position: number) {
|
||||
return getLineAndCharacterOfPosition(getLineStarts(), position);
|
||||
}
|
||||
|
||||
function getPositionFromSourceLineAndCharacter(line: number, character: number): number {
|
||||
if (!lineStarts) {
|
||||
lineStarts = getLineStarts(sourceText);
|
||||
}
|
||||
return getPositionFromLineAndCharacter(lineStarts, line, character);
|
||||
return getPositionFromLineAndCharacter(getLineStarts(), line, character);
|
||||
}
|
||||
|
||||
function error(message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): void {
|
||||
@@ -1006,7 +1012,9 @@ module ts {
|
||||
? file.syntacticErrors[file.syntacticErrors.length - 1].start
|
||||
: -1;
|
||||
if (start !== lastErrorPos) {
|
||||
file.syntacticErrors.push(createFileDiagnostic(file, start, length, message, arg0, arg1, arg2));
|
||||
var diagnostic = createFileDiagnostic(file, start, length, message, arg0, arg1, arg2);
|
||||
diagnostic.isParseError = true;
|
||||
file.syntacticErrors.push(diagnostic);
|
||||
}
|
||||
|
||||
if (lookAheadMode === LookAheadMode.NoErrorYet) {
|
||||
@@ -1674,8 +1682,8 @@ module ts {
|
||||
}
|
||||
|
||||
return {
|
||||
typeParameters: typeParameters,
|
||||
parameters: parameters,
|
||||
typeParameters,
|
||||
parameters,
|
||||
type: type
|
||||
};
|
||||
}
|
||||
@@ -1886,16 +1894,16 @@ module ts {
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseFunctionType(signatureKind: SyntaxKind): TypeLiteralNode {
|
||||
var node = <TypeLiteralNode>createNode(SyntaxKind.TypeLiteral);
|
||||
var member = <SignatureDeclaration>createNode(signatureKind);
|
||||
var sig = parseSignature(signatureKind, SyntaxKind.EqualsGreaterThanToken, /* returnTokenRequired */ true);
|
||||
function parseFunctionType(typeKind: SyntaxKind): SignatureDeclaration {
|
||||
var member = <SignatureDeclaration>createNode(typeKind);
|
||||
var sig = parseSignature(typeKind === SyntaxKind.FunctionType ? SyntaxKind.CallSignature : SyntaxKind.ConstructSignature,
|
||||
SyntaxKind.EqualsGreaterThanToken, /* returnTokenRequired */ true);
|
||||
|
||||
member.typeParameters = sig.typeParameters;
|
||||
member.parameters = sig.parameters;
|
||||
member.type = sig.type;
|
||||
finishNode(member);
|
||||
node.members = createNodeArray(member);
|
||||
return finishNode(node);
|
||||
return member;
|
||||
}
|
||||
|
||||
function parseKeywordAndNoDot(): Node {
|
||||
@@ -2015,10 +2023,10 @@ module ts {
|
||||
|
||||
function parseType(): TypeNode {
|
||||
if (isStartOfFunctionType()) {
|
||||
return parseFunctionType(SyntaxKind.CallSignature);
|
||||
return parseFunctionType(SyntaxKind.FunctionType);
|
||||
}
|
||||
if (token === SyntaxKind.NewKeyword) {
|
||||
return parseFunctionType(SyntaxKind.ConstructSignature);
|
||||
return parseFunctionType(SyntaxKind.ConstructorType);
|
||||
}
|
||||
return parseUnionType();
|
||||
}
|
||||
@@ -2731,10 +2739,14 @@ module ts {
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parsePropertyAssignment(): PropertyDeclaration {
|
||||
var node = <PropertyDeclaration>createNode(SyntaxKind.PropertyAssignment);
|
||||
node.name = parsePropertyName();
|
||||
function parsePropertyAssignment(): Declaration {
|
||||
var nodePos = scanner.getStartPos();
|
||||
var nameToken = token;
|
||||
var propertyName = parsePropertyName();
|
||||
var node: Declaration;
|
||||
if (token === SyntaxKind.OpenParenToken || token === SyntaxKind.LessThanToken) {
|
||||
node = <PropertyDeclaration>createNode(SyntaxKind.PropertyAssignment, nodePos);
|
||||
node.name = propertyName;
|
||||
var sig = parseSignature(SyntaxKind.CallSignature, SyntaxKind.ColonToken, /* returnTokenRequired */ false);
|
||||
var body = parseBody(/* ignoreMissingOpenBrace */ false);
|
||||
// do not propagate property name as name for function expression
|
||||
@@ -2742,11 +2754,26 @@ module ts {
|
||||
// var x = 1;
|
||||
// var y = { x() { } }
|
||||
// otherwise this will bring y.x into the scope of x which is incorrect
|
||||
node.initializer = makeFunctionExpression(SyntaxKind.FunctionExpression, node.pos, undefined, sig, body);
|
||||
(<PropertyDeclaration>node).initializer = makeFunctionExpression(SyntaxKind.FunctionExpression, node.pos, undefined, sig, body);
|
||||
return finishNode(node);
|
||||
}
|
||||
// Disallow optional property assignment
|
||||
if (token === SyntaxKind.QuestionToken) {
|
||||
var questionStart = scanner.getTokenPos();
|
||||
grammarErrorAtPos(questionStart, scanner.getStartPos() - questionStart, Diagnostics.A_object_member_cannot_be_declared_optional);
|
||||
nextToken();
|
||||
}
|
||||
|
||||
// Parse to check if it is short-hand property assignment or normal property assignment
|
||||
if (token !== SyntaxKind.ColonToken && nameToken === SyntaxKind.Identifier) {
|
||||
node = <ShortHandPropertyDeclaration>createNode(SyntaxKind.ShorthandPropertyAssignment, nodePos);
|
||||
node.name = propertyName;
|
||||
}
|
||||
else {
|
||||
node = <PropertyDeclaration>createNode(SyntaxKind.PropertyAssignment, nodePos);
|
||||
node.name = propertyName;
|
||||
parseExpected(SyntaxKind.ColonToken);
|
||||
node.initializer = parseAssignmentExpression(false);
|
||||
(<PropertyDeclaration>node).initializer = parseAssignmentExpression(false);
|
||||
}
|
||||
return finishNode(node);
|
||||
}
|
||||
@@ -2796,6 +2823,9 @@ module ts {
|
||||
if (p.kind === SyntaxKind.PropertyAssignment) {
|
||||
currentKind = Property;
|
||||
}
|
||||
else if (p.kind === SyntaxKind.ShorthandPropertyAssignment) {
|
||||
currentKind = Property;
|
||||
}
|
||||
else if (p.kind === SyntaxKind.GetAccessor) {
|
||||
currentKind = GetAccessor;
|
||||
}
|
||||
@@ -4226,6 +4256,7 @@ module ts {
|
||||
function processReferenceComments(): ReferenceComments {
|
||||
var referencedFiles: FileReference[] = [];
|
||||
var amdDependencies: string[] = [];
|
||||
var amdModuleName: string;
|
||||
commentRanges = [];
|
||||
token = scanner.scan();
|
||||
|
||||
@@ -4245,6 +4276,15 @@ module ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
var amdModuleNameRegEx = /^\/\/\/\s*<amd-module\s+name\s*=\s*('|")(.+?)\1/gim;
|
||||
var amdModuleNameMatchResult = amdModuleNameRegEx.exec(comment);
|
||||
if(amdModuleNameMatchResult) {
|
||||
if(amdModuleName) {
|
||||
errorAtPos(range.pos, range.end - range.pos, Diagnostics.An_AMD_module_cannot_have_multiple_name_assignments);
|
||||
}
|
||||
amdModuleName = amdModuleNameMatchResult[2];
|
||||
}
|
||||
|
||||
var amdDependencyRegEx = /^\/\/\/\s*<amd-dependency\s+path\s*=\s*('|")(.+?)\1/gim;
|
||||
var amdDependencyMatchResult = amdDependencyRegEx.exec(comment);
|
||||
if (amdDependencyMatchResult) {
|
||||
@@ -4254,8 +4294,9 @@ module ts {
|
||||
}
|
||||
commentRanges = undefined;
|
||||
return {
|
||||
referencedFiles: referencedFiles,
|
||||
amdDependencies: amdDependencies
|
||||
referencedFiles,
|
||||
amdDependencies,
|
||||
amdModuleName
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4277,13 +4318,15 @@ module ts {
|
||||
file = <SourceFile>createRootNode(SyntaxKind.SourceFile, 0, sourceText.length, rootNodeFlags);
|
||||
file.filename = normalizePath(filename);
|
||||
file.text = sourceText;
|
||||
file.getLineAndCharacterFromPosition = getLineAndCharacterlFromSourcePosition;
|
||||
file.getLineAndCharacterFromPosition = getLineAndCharacterFromSourcePosition;
|
||||
file.getPositionFromLineAndCharacter = getPositionFromSourceLineAndCharacter;
|
||||
file.getLineStarts = getLineStarts;
|
||||
file.syntacticErrors = [];
|
||||
file.semanticErrors = [];
|
||||
var referenceComments = processReferenceComments();
|
||||
file.referencedFiles = referenceComments.referencedFiles;
|
||||
file.amdDependencies = referenceComments.amdDependencies;
|
||||
file.amdModuleName = referenceComments.amdModuleName;
|
||||
file.statements = parseList(ParsingContext.SourceElements, /*checkForStrictMode*/ true, parseSourceElement);
|
||||
file.externalModuleIndicator = getExternalModuleIndicator();
|
||||
file.nodeCount = nodeCount;
|
||||
|
||||
+21
-20
@@ -246,7 +246,7 @@ module ts {
|
||||
return tokenStrings[t];
|
||||
}
|
||||
|
||||
export function getLineStarts(text: string): number[] {
|
||||
export function computeLineStarts(text: string): number[] {
|
||||
var result: number[] = new Array();
|
||||
var pos = 0;
|
||||
var lineStart = 0;
|
||||
@@ -294,7 +294,7 @@ module ts {
|
||||
}
|
||||
|
||||
export function positionToLineAndCharacter(text: string, pos: number) {
|
||||
var lineStarts = getLineStarts(text);
|
||||
var lineStarts = computeLineStarts(text);
|
||||
return getLineAndCharacterOfPosition(lineStarts, pos);
|
||||
}
|
||||
|
||||
@@ -553,7 +553,7 @@ module ts {
|
||||
while (true) {
|
||||
if (pos >= len) {
|
||||
result += text.substring(start, pos);
|
||||
error(Diagnostics.Unexpected_end_of_text);
|
||||
error(Diagnostics.Unterminated_string_literal);
|
||||
break;
|
||||
}
|
||||
var ch = text.charCodeAt(pos);
|
||||
@@ -593,7 +593,7 @@ module ts {
|
||||
while (true) {
|
||||
if (pos >= len) {
|
||||
contents += text.substring(start, pos);
|
||||
error(Diagnostics.Unexpected_end_of_text);
|
||||
error(Diagnostics.Unterminated_template_literal);
|
||||
resultingToken = startedWithBacktick ? SyntaxKind.NoSubstitutionTemplateLiteral : SyntaxKind.TemplateTail;
|
||||
break;
|
||||
}
|
||||
@@ -1066,19 +1066,19 @@ module ts {
|
||||
var inEscape = false;
|
||||
var inCharacterClass = false;
|
||||
while (true) {
|
||||
// If we've hit EOF without closing off the regex,
|
||||
// simply return the token we originally parsed.
|
||||
// If we reach the end of a file, or hit a newline, then this is an unterminated
|
||||
// regex. Report error and return what we have so far.
|
||||
if (p >= len) {
|
||||
return token;
|
||||
error(Diagnostics.Unterminated_regular_expression_literal)
|
||||
break;
|
||||
}
|
||||
|
||||
var ch = text.charCodeAt(p);
|
||||
|
||||
// Line breaks are not permissible in the middle of a RegExp.
|
||||
if (isLineBreak(ch)) {
|
||||
return token;
|
||||
error(Diagnostics.Unterminated_regular_expression_literal)
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (inEscape) {
|
||||
// Parsing an escape character;
|
||||
// reset the flag and just advance to the next char.
|
||||
@@ -1087,6 +1087,7 @@ module ts {
|
||||
else if (ch === CharacterCodes.slash && !inCharacterClass) {
|
||||
// A slash within a character class is permissible,
|
||||
// but in general it signals the end of the regexp literal.
|
||||
p++;
|
||||
break;
|
||||
}
|
||||
else if (ch === CharacterCodes.openBracket) {
|
||||
@@ -1100,8 +1101,8 @@ module ts {
|
||||
}
|
||||
p++;
|
||||
}
|
||||
p++;
|
||||
while (isIdentifierPart(text.charCodeAt(p))) {
|
||||
|
||||
while (p < len && isIdentifierPart(text.charCodeAt(p))) {
|
||||
p++;
|
||||
}
|
||||
pos = p;
|
||||
@@ -1166,13 +1167,13 @@ module ts {
|
||||
hasPrecedingLineBreak: () => precedingLineBreak,
|
||||
isIdentifier: () => token === SyntaxKind.Identifier || token > SyntaxKind.LastReservedWord,
|
||||
isReservedWord: () => token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord,
|
||||
reScanGreaterToken: reScanGreaterToken,
|
||||
reScanSlashToken: reScanSlashToken,
|
||||
reScanTemplateToken: reScanTemplateToken,
|
||||
scan: scan,
|
||||
setText: setText,
|
||||
setTextPos: setTextPos,
|
||||
tryScan: tryScan,
|
||||
reScanGreaterToken,
|
||||
reScanSlashToken,
|
||||
reScanTemplateToken,
|
||||
scan,
|
||||
setText,
|
||||
setTextPos,
|
||||
tryScan,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -99,14 +99,14 @@ var sys: System = (function () {
|
||||
}
|
||||
|
||||
return {
|
||||
args: args,
|
||||
args,
|
||||
newLine: "\r\n",
|
||||
useCaseSensitiveFileNames: false,
|
||||
write(s: string): void {
|
||||
WScript.StdOut.Write(s);
|
||||
},
|
||||
readFile: readFile,
|
||||
writeFile: writeFile,
|
||||
readFile,
|
||||
writeFile,
|
||||
resolvePath(path: string): string {
|
||||
return fso.GetAbsolutePathName(path);
|
||||
},
|
||||
@@ -191,8 +191,8 @@ var sys: System = (function () {
|
||||
// 1 is a standard descriptor for stdout
|
||||
_fs.writeSync(1, s);
|
||||
},
|
||||
readFile: readFile,
|
||||
writeFile: writeFile,
|
||||
readFile,
|
||||
writeFile,
|
||||
watchFile: (fileName, callback) => {
|
||||
// watchFile polls a file every 250ms, picking up file notifications.
|
||||
_fs.watchFile(fileName, { persistent: true, interval: 250 }, fileChanged);
|
||||
|
||||
+10
-10
@@ -192,12 +192,12 @@ module ts {
|
||||
}
|
||||
|
||||
return {
|
||||
getSourceFile: getSourceFile,
|
||||
getSourceFile,
|
||||
getDefaultLibFilename: () => combinePaths(getDirectoryPath(normalizePath(sys.getExecutingFilePath())), "lib.d.ts"),
|
||||
writeFile: writeFile,
|
||||
writeFile,
|
||||
getCurrentDirectory: () => currentDirectory || (currentDirectory = sys.getCurrentDirectory()),
|
||||
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
|
||||
getCanonicalFileName: getCanonicalFileName,
|
||||
getCanonicalFileName,
|
||||
getNewLine: () => sys.newLine
|
||||
};
|
||||
}
|
||||
@@ -362,17 +362,17 @@ module ts {
|
||||
var checker = program.getTypeChecker(/*fullTypeCheckMode*/ true);
|
||||
var checkStart = new Date().getTime();
|
||||
errors = checker.getDiagnostics();
|
||||
if (!checker.hasEarlyErrors()) {
|
||||
if (checker.isEmitBlocked()) {
|
||||
exitStatus = EmitReturnStatus.AllOutputGenerationSkipped;
|
||||
}
|
||||
else {
|
||||
var emitStart = new Date().getTime();
|
||||
var emitOutput = checker.emitFiles();
|
||||
var emitErrors = emitOutput.errors;
|
||||
var emitOutput = checker.invokeEmitter();
|
||||
var emitErrors = emitOutput.diagnostics;
|
||||
exitStatus = emitOutput.emitResultStatus;
|
||||
var reportStart = new Date().getTime();
|
||||
errors = concatenate(errors, emitErrors);
|
||||
}
|
||||
else {
|
||||
exitStatus = EmitReturnStatus.AllOutputGenerationSkipped;
|
||||
}
|
||||
}
|
||||
|
||||
reportDiagnostics(errors);
|
||||
@@ -394,7 +394,7 @@ module ts {
|
||||
reportTimeStatistic("Total time", reportStart - parseStart);
|
||||
}
|
||||
|
||||
return { program: program, exitStatus: exitStatus }
|
||||
return { program, exitStatus };
|
||||
}
|
||||
|
||||
function printVersion() {
|
||||
|
||||
+31
-7
@@ -155,6 +155,8 @@ module ts {
|
||||
IndexSignature,
|
||||
// Type
|
||||
TypeReference,
|
||||
FunctionType,
|
||||
ConstructorType,
|
||||
TypeQuery,
|
||||
TypeLiteral,
|
||||
ArrayType,
|
||||
@@ -165,6 +167,7 @@ module ts {
|
||||
ArrayLiteral,
|
||||
ObjectLiteral,
|
||||
PropertyAssignment,
|
||||
ShorthandPropertyAssignment,
|
||||
PropertyAccess,
|
||||
IndexedAccess,
|
||||
CallExpression,
|
||||
@@ -245,7 +248,11 @@ module ts {
|
||||
FirstLiteralToken = NumericLiteral,
|
||||
LastLiteralToken = NoSubstitutionTemplateLiteral,
|
||||
FirstTemplateToken = NoSubstitutionTemplateLiteral,
|
||||
LastTemplateToken = TemplateTail
|
||||
LastTemplateToken = TemplateTail,
|
||||
FirstOperator = SemicolonToken,
|
||||
LastOperator = CaretEqualsToken,
|
||||
FirstBinaryOperator = LessThanToken,
|
||||
LastBinaryOperator = CaretEqualsToken
|
||||
}
|
||||
|
||||
export const enum NodeFlags {
|
||||
@@ -329,6 +336,10 @@ module ts {
|
||||
initializer?: Expression;
|
||||
}
|
||||
|
||||
export interface ShortHandPropertyDeclaration extends Declaration {
|
||||
name: Identifier;
|
||||
}
|
||||
|
||||
export interface ParameterDeclaration extends VariableDeclaration { }
|
||||
|
||||
/**
|
||||
@@ -627,9 +638,11 @@ module ts {
|
||||
export interface SourceFile extends Block {
|
||||
filename: string;
|
||||
text: string;
|
||||
getLineAndCharacterFromPosition(position: number): { line: number; character: number };
|
||||
getLineAndCharacterFromPosition(position: number): LineAndCharacter;
|
||||
getPositionFromLineAndCharacter(line: number, character: number): number;
|
||||
getLineStarts(): number[];
|
||||
amdDependencies: string[];
|
||||
amdModuleName: string;
|
||||
referencedFiles: FileReference[];
|
||||
syntacticErrors: Diagnostic[];
|
||||
semanticErrors: Diagnostic[];
|
||||
@@ -688,7 +701,7 @@ module ts {
|
||||
|
||||
export interface EmitResult {
|
||||
emitResultStatus: EmitReturnStatus;
|
||||
errors: Diagnostic[];
|
||||
diagnostics: Diagnostic[];
|
||||
sourceMaps: SourceMapData[]; // Array of sourceMapData if compiler emitted sourcemaps
|
||||
}
|
||||
|
||||
@@ -701,7 +714,7 @@ module ts {
|
||||
getSymbolCount(): number;
|
||||
getTypeCount(): number;
|
||||
checkProgram(): void;
|
||||
emitFiles(targetSourceFile?: SourceFile): EmitResult;
|
||||
invokeEmitter(targetSourceFile?: SourceFile): EmitResult;
|
||||
getParentOfSymbol(symbol: Symbol): Symbol;
|
||||
getNarrowedTypeOfSymbol(symbol: Symbol, node: Node): Type;
|
||||
getDeclaredTypeOfSymbol(symbol: Symbol): Type;
|
||||
@@ -712,6 +725,7 @@ module ts {
|
||||
getReturnTypeOfSignature(signature: Signature): Type;
|
||||
getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[];
|
||||
getSymbolInfo(node: Node): Symbol;
|
||||
getShorthandAssignmentValueSymbol(location: Node): Symbol;
|
||||
getTypeOfNode(node: Node): Type;
|
||||
typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string;
|
||||
symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string;
|
||||
@@ -724,8 +738,8 @@ module ts {
|
||||
getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature;
|
||||
isImplementationOfOverload(node: FunctionLikeDeclaration): boolean;
|
||||
isUndefinedSymbol(symbol: Symbol): boolean;
|
||||
isArgumentsSymbol(symbol: Symbol): boolean;
|
||||
hasEarlyErrors(sourceFile?: SourceFile): boolean;
|
||||
isArgumentsSymbol(symbol: Symbol): boolean;
|
||||
isEmitBlocked(sourceFile?: SourceFile): boolean;
|
||||
// Returns the constant value of this enum member, or 'undefined' if the enum member has a computed value.
|
||||
getEnumMemberValue(node: EnumMember): number;
|
||||
isValidPropertyAccess(node: PropertyAccess, propertyName: string): boolean;
|
||||
@@ -816,7 +830,7 @@ module ts {
|
||||
isImportDeclarationEntityNameReferenceDeclarationVisibile(entityName: EntityName): SymbolAccessiblityResult;
|
||||
// Returns the constant value this property access resolves to, or 'undefined' for a non-constant
|
||||
getConstantValue(node: PropertyAccess | IndexedAccess): number;
|
||||
hasEarlyErrors(sourceFile?: SourceFile): boolean;
|
||||
isEmitBlocked(sourceFile?: SourceFile): boolean;
|
||||
}
|
||||
|
||||
export const enum SymbolFlags {
|
||||
@@ -1121,7 +1135,16 @@ module ts {
|
||||
messageText: string;
|
||||
category: DiagnosticCategory;
|
||||
code: number;
|
||||
/**
|
||||
* Early error - any error (can be produced at parsing\binding\typechecking step) that blocks emit
|
||||
*/
|
||||
isEarly?: boolean;
|
||||
/**
|
||||
* Parse error - error produced by parser when it scanner returns a token
|
||||
* that parser does not understand in its current state
|
||||
* (as opposed to grammar error when parser can interpret the token but interpretation is not legal from the grammar perespective)
|
||||
*/
|
||||
isParseError?: boolean;
|
||||
}
|
||||
|
||||
export enum DiagnosticCategory {
|
||||
@@ -1140,6 +1163,7 @@ module ts {
|
||||
locale?: string;
|
||||
mapRoot?: string;
|
||||
module?: ModuleKind;
|
||||
noEmitOnError?: boolean;
|
||||
noErrorTruncation?: boolean;
|
||||
noImplicitAny?: boolean;
|
||||
noLib?: boolean;
|
||||
|
||||
@@ -175,7 +175,12 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
it('Correct sourcemap content for ' + fileName, () => {
|
||||
if (options.sourceMap) {
|
||||
Harness.Baseline.runBaseline('Correct sourcemap content for ' + fileName, justName.replace(/\.ts$/, '.sourcemap.txt'), () => {
|
||||
return result.getSourceMapRecord();
|
||||
var record = result.getSourceMapRecord();
|
||||
if (options.noEmitOnError && result.errors.length !== 0 && record === undefined) {
|
||||
// Because of the noEmitOnError option no files are created. We need to return null because baselining isn't required.
|
||||
return null;
|
||||
}
|
||||
return record;
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -246,6 +251,12 @@ class CompilerBaselineRunner extends RunnerBase {
|
||||
}
|
||||
|
||||
Harness.Baseline.runBaseline('Correct Sourcemap output for ' + fileName, justName.replace(/\.ts/, '.js.map'), () => {
|
||||
if (options.noEmitOnError && result.errors.length !== 0 && result.sourceMaps.length === 0) {
|
||||
// We need to return null here or the runBaseLine will actually create a empty file.
|
||||
// Baselining isn't required here because there is no output.
|
||||
return null;
|
||||
}
|
||||
|
||||
var sourceMapCode = '';
|
||||
for (var i = 0; i < result.sourceMaps.length; i++) {
|
||||
sourceMapCode += '//// [' + Harness.Path.getFileName(result.sourceMaps[i].fileName) + ']\r\n';
|
||||
|
||||
+30
-55
@@ -215,7 +215,7 @@ module FourSlash {
|
||||
}
|
||||
|
||||
public setCancelled(numberOfCalls: number = 0): void {
|
||||
TypeScript.Debug.assert(numberOfCalls >= 0);
|
||||
ts.Debug.assert(numberOfCalls >= 0);
|
||||
this.numberOfCallsBeforeCancellation = numberOfCalls;
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ module FourSlash {
|
||||
|
||||
// This function creates IScriptSnapshot object for testing getPreProcessedFileInfo
|
||||
// Return object may lack some functionalities for other purposes.
|
||||
function createScriptSnapShot(sourceText: string): TypeScript.IScriptSnapshot {
|
||||
function createScriptSnapShot(sourceText: string): ts.IScriptSnapshot {
|
||||
return {
|
||||
getText: (start: number, end: number) => {
|
||||
return sourceText.substr(start, end - start);
|
||||
@@ -250,8 +250,8 @@ module FourSlash {
|
||||
getLineStartPositions: () => {
|
||||
return <number[]>[];
|
||||
},
|
||||
getChangeRange: (oldSnapshot: TypeScript.IScriptSnapshot) => {
|
||||
return <TypeScript.TextChangeRange>undefined;
|
||||
getChangeRange: (oldSnapshot: ts.IScriptSnapshot) => {
|
||||
return <ts.TextChangeRange>undefined;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -262,7 +262,7 @@ module FourSlash {
|
||||
private languageService: ts.LanguageService;
|
||||
|
||||
// A reference to the language service's compiler state's compiler instance
|
||||
private compiler: () => { getSyntaxTree(fileName: string): TypeScript.SyntaxTree; getSourceUnit(fileName: string): TypeScript.SourceUnitSyntax; };
|
||||
private compiler: () => { getSyntaxTree(fileName: string): ts.SourceFile };
|
||||
|
||||
// The current caret position in the active file
|
||||
public currentCaretPosition = 0;
|
||||
@@ -403,8 +403,9 @@ module FourSlash {
|
||||
public goToPosition(pos: number) {
|
||||
this.currentCaretPosition = pos;
|
||||
|
||||
var lineCharPos = TypeScript.LineMap1.fromString(this.getCurrentFileContent()).getLineAndCharacterFromPosition(pos);
|
||||
this.scenarioActions.push('<MoveCaretToLineAndChar LineNumber="' + (lineCharPos.line() + 1) + '" CharNumber="' + (lineCharPos.character() + 1) + '" />');
|
||||
var lineStarts = ts.computeLineStarts(this.getCurrentFileContent());
|
||||
var lineCharPos = ts.getLineAndCharacterOfPosition(lineStarts, pos);
|
||||
this.scenarioActions.push('<MoveCaretToLineAndChar LineNumber="' + lineCharPos.line + '" CharNumber="' + lineCharPos.character + '" />');
|
||||
}
|
||||
|
||||
public moveCaretRight(count = 1) {
|
||||
@@ -748,29 +749,6 @@ module FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public verifyImplementorsCountIs(count: number, localFilesOnly: boolean = true) {
|
||||
var implementors = this.getImplementorsAtCaret();
|
||||
var implementorsCount = 0;
|
||||
|
||||
if (localFilesOnly) {
|
||||
var localFiles = this.testData.files.map<string>(file => file.fileName);
|
||||
// Count only the references in local files. Filter the ones in lib and other files.
|
||||
implementors.forEach((entry) => {
|
||||
if (localFiles.some((filename) => filename === entry.fileName)) {
|
||||
++implementorsCount;
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
implementorsCount = implementors.length;
|
||||
}
|
||||
|
||||
if (implementorsCount !== count) {
|
||||
var condition = localFilesOnly ? "excluding libs" : "including libs";
|
||||
this.raiseError("Expected implementors count (" + condition + ") to be " + count + ", but is actually " + implementors.length);
|
||||
}
|
||||
}
|
||||
|
||||
private getMemberListAtCaret() {
|
||||
return this.languageService.getCompletionsAtPosition(this.activeFile.fileName, this.currentCaretPosition, true);
|
||||
}
|
||||
@@ -787,10 +765,6 @@ module FourSlash {
|
||||
return this.languageService.getReferencesAtPosition(this.activeFile.fileName, this.currentCaretPosition);
|
||||
}
|
||||
|
||||
private getImplementorsAtCaret() {
|
||||
return this.languageService.getImplementorsAtPosition(this.activeFile.fileName, this.currentCaretPosition);
|
||||
}
|
||||
|
||||
private assertionMessage(name: string, actualValue: any, expectedValue: any) {
|
||||
return "\nActual " + name + ":\n\t" + actualValue + "\nExpected value:\n\t" + expectedValue;
|
||||
}
|
||||
@@ -1017,11 +991,11 @@ module FourSlash {
|
||||
|
||||
private alignmentForExtraInfo = 50;
|
||||
|
||||
private spanInfoToString(pos: number, spanInfo: TypeScript.TextSpan, prefixString: string) {
|
||||
private spanInfoToString(pos: number, spanInfo: ts.TextSpan, prefixString: string) {
|
||||
var resultString = "SpanInfo: " + JSON.stringify(spanInfo);
|
||||
if (spanInfo) {
|
||||
var spanString = this.activeFile.content.substr(spanInfo.start(), spanInfo.length());
|
||||
var spanLineMap = ts.getLineStarts(spanString);
|
||||
var spanLineMap = ts.computeLineStarts(spanString);
|
||||
for (var i = 0; i < spanLineMap.length; i++) {
|
||||
if (!i) {
|
||||
resultString += "\n";
|
||||
@@ -1034,8 +1008,8 @@ module FourSlash {
|
||||
return resultString;
|
||||
}
|
||||
|
||||
private baselineCurrentFileLocations(getSpanAtPos: (pos: number) => TypeScript.TextSpan): string {
|
||||
var fileLineMap = ts.getLineStarts(this.activeFile.content);
|
||||
private baselineCurrentFileLocations(getSpanAtPos: (pos: number) => ts.TextSpan): string {
|
||||
var fileLineMap = ts.computeLineStarts(this.activeFile.content);
|
||||
var nextLine = 0;
|
||||
var resultString = "";
|
||||
var currentLine: string;
|
||||
@@ -1748,14 +1722,14 @@ module FourSlash {
|
||||
|
||||
public verifySemanticClassifications(expected: { classificationType: string; text: string }[]) {
|
||||
var actual = this.languageService.getSemanticClassifications(this.activeFile.fileName,
|
||||
new TypeScript.TextSpan(0, this.activeFile.content.length));
|
||||
new ts.TextSpan(0, this.activeFile.content.length));
|
||||
|
||||
this.verifyClassifications(expected, actual);
|
||||
}
|
||||
|
||||
public verifySyntacticClassifications(expected: { classificationType: string; text: string }[]) {
|
||||
var actual = this.languageService.getSyntacticClassifications(this.activeFile.fileName,
|
||||
new TypeScript.TextSpan(0, this.activeFile.content.length));
|
||||
new ts.TextSpan(0, this.activeFile.content.length));
|
||||
|
||||
this.verifyClassifications(expected, actual);
|
||||
}
|
||||
@@ -1789,7 +1763,7 @@ module FourSlash {
|
||||
for (var i = 0; i < spans.length; i++) {
|
||||
var expectedSpan = spans[i];
|
||||
var actualComment = actual[i];
|
||||
var actualCommentSpan = new TypeScript.TextSpan(actualComment.position, actualComment.message.length);
|
||||
var actualCommentSpan = new ts.TextSpan(actualComment.position, actualComment.message.length);
|
||||
|
||||
if (expectedSpan.start !== actualCommentSpan.start() || expectedSpan.end !== actualCommentSpan.end()) {
|
||||
this.raiseError('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualCommentSpan.start() + ',' + actualCommentSpan.end() + ')');
|
||||
@@ -2240,15 +2214,16 @@ module FourSlash {
|
||||
(fn, contents) => result = contents,
|
||||
ts.ScriptTarget.Latest,
|
||||
sys.useCaseSensitiveFileNames);
|
||||
var program = ts.createProgram([Harness.Compiler.fourslashFilename, fileName], { out: "fourslashTestOutput.js" }, host);
|
||||
// TODO (drosen): We need to enforce checking on these tests.
|
||||
var program = ts.createProgram([Harness.Compiler.fourslashFilename, fileName], { out: "fourslashTestOutput.js", noResolve: true }, host);
|
||||
var checker = ts.createTypeChecker(program, /*fullTypeCheckMode*/ true);
|
||||
checker.checkProgram();
|
||||
|
||||
var errs = checker.getDiagnostics(program.getSourceFile(fileName));
|
||||
var errs = program.getDiagnostics().concat(checker.getDiagnostics());
|
||||
if (errs.length > 0) {
|
||||
throw new Error('Error compiling ' + fileName + ': ' + errs.map(e => e.messageText).join('\r\n'));
|
||||
}
|
||||
checker.emitFiles();
|
||||
checker.invokeEmitter();
|
||||
result = result || ''; // Might have an empty fourslash file
|
||||
|
||||
// Compile and execute the test
|
||||
@@ -2282,7 +2257,7 @@ module FourSlash {
|
||||
// List of all the subfiles we've parsed out
|
||||
var files: FourSlashFile[] = [];
|
||||
// Global options
|
||||
var opts: { [s: string]: string; } = {};
|
||||
var globalOptions: { [s: string]: string; } = {};
|
||||
// Marker positions
|
||||
|
||||
// Split up the input file by line
|
||||
@@ -2290,7 +2265,7 @@ module FourSlash {
|
||||
// we have to string-based splitting instead and try to figure out the delimiting chars
|
||||
var lines = contents.split('\n');
|
||||
|
||||
var markerMap: MarkerMap = {};
|
||||
var markerPositions: MarkerMap = {};
|
||||
var markers: Marker[] = [];
|
||||
var ranges: Range[] = [];
|
||||
|
||||
@@ -2331,7 +2306,7 @@ module FourSlash {
|
||||
} else if (fileMetadataNamesIndex === fileMetadataNames.indexOf(testOptMetadataNames.filename)) {
|
||||
// Found an @Filename directive, if this is not the first then create a new subfile
|
||||
if (currentFileContent) {
|
||||
var file = parseFileContent(currentFileContent, currentFileName, markerMap, markers, ranges);
|
||||
var file = parseFileContent(currentFileContent, currentFileName, markerPositions, markers, ranges);
|
||||
file.fileOptions = currentFileOptions;
|
||||
|
||||
// Store result file
|
||||
@@ -2351,10 +2326,10 @@ module FourSlash {
|
||||
}
|
||||
} else {
|
||||
// Check if the match is already existed in the global options
|
||||
if (opts[match[1]] !== undefined) {
|
||||
if (globalOptions[match[1]] !== undefined) {
|
||||
throw new Error("Global Option : '" + match[1] + "' is already existed");
|
||||
}
|
||||
opts[match[1]] = match[2];
|
||||
globalOptions[match[1]] = match[2];
|
||||
}
|
||||
}
|
||||
} else if (line == '' || lineLength === 0) {
|
||||
@@ -2363,7 +2338,7 @@ module FourSlash {
|
||||
} else {
|
||||
// Empty line or code line, terminate current subfile if there is one
|
||||
if (currentFileContent) {
|
||||
var file = parseFileContent(currentFileContent, currentFileName, markerMap, markers, ranges);
|
||||
var file = parseFileContent(currentFileContent, currentFileName, markerPositions, markers, ranges);
|
||||
file.fileOptions = currentFileOptions;
|
||||
|
||||
// Store result file
|
||||
@@ -2378,11 +2353,11 @@ module FourSlash {
|
||||
}
|
||||
|
||||
return {
|
||||
markerPositions: markerMap,
|
||||
markers: markers,
|
||||
globalOptions: opts,
|
||||
files: files,
|
||||
ranges: ranges
|
||||
markerPositions,
|
||||
markers,
|
||||
globalOptions,
|
||||
files,
|
||||
ranges
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+26
-19
@@ -15,6 +15,7 @@
|
||||
|
||||
/// <reference path='..\services\services.ts' />
|
||||
/// <reference path='..\services\shims.ts' />
|
||||
/// <reference path='..\compiler\core.ts' />
|
||||
/// <reference path='..\compiler\sys.ts' />
|
||||
/// <reference path='external\mocha.d.ts'/>
|
||||
/// <reference path='external\chai.d.ts'/>
|
||||
@@ -584,12 +585,12 @@ module Harness {
|
||||
return defaultLibSourceFile;
|
||||
}
|
||||
// Don't throw here -- the compiler might be looking for a test that actually doesn't exist as part of the TC
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
},
|
||||
getDefaultLibFilename: () => defaultLibFileName,
|
||||
writeFile: writeFile,
|
||||
getCanonicalFileName: getCanonicalFileName,
|
||||
writeFile,
|
||||
getCanonicalFileName,
|
||||
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
|
||||
getNewLine: ()=> sys.newLine
|
||||
};
|
||||
@@ -699,6 +700,10 @@ module Harness {
|
||||
}
|
||||
break;
|
||||
|
||||
case 'noemitonerror':
|
||||
options.noEmitOnError = !!setting.value;
|
||||
break;
|
||||
|
||||
case 'noresolve':
|
||||
options.noResolve = !!setting.value;
|
||||
break;
|
||||
@@ -793,21 +798,19 @@ module Harness {
|
||||
options.target,
|
||||
useCaseSensitiveFileNames));
|
||||
|
||||
var hadParseErrors = program.getDiagnostics().length > 0;
|
||||
|
||||
var checker = program.getTypeChecker(/*fullTypeCheckMode*/ true);
|
||||
checker.checkProgram();
|
||||
|
||||
var hasEarlyErrors = checker.hasEarlyErrors();
|
||||
var isEmitBlocked = checker.isEmitBlocked();
|
||||
|
||||
// only emit if there weren't parse errors
|
||||
var emitResult: ts.EmitResult;
|
||||
if (!hadParseErrors && !hasEarlyErrors) {
|
||||
emitResult = checker.emitFiles();
|
||||
if (!isEmitBlocked) {
|
||||
emitResult = checker.invokeEmitter();
|
||||
}
|
||||
|
||||
var errors: HarnessDiagnostic[] = [];
|
||||
program.getDiagnostics().concat(checker.getDiagnostics()).concat(emitResult ? emitResult.errors : []).forEach(err => {
|
||||
program.getDiagnostics().concat(checker.getDiagnostics()).concat(emitResult ? emitResult.diagnostics : []).forEach(err => {
|
||||
// TODO: new compiler formats errors after this point to add . and newlines so we'll just do it manually for now
|
||||
errors.push(getMinimalDiagnostic(err));
|
||||
});
|
||||
@@ -842,7 +845,7 @@ module Harness {
|
||||
declResult = compileResult;
|
||||
}, settingsCallback, options);
|
||||
|
||||
return { declInputFiles: declInputFiles, declOtherFiles: declOtherFiles, declResult: declResult };
|
||||
return { declInputFiles, declOtherFiles, declResult };
|
||||
}
|
||||
|
||||
function addDtsFile(file: { unitName: string; content: string }, dtsFiles: { unitName: string; content: string }[]) {
|
||||
@@ -957,7 +960,7 @@ module Harness {
|
||||
// Note: IE JS engine incorrectly handles consecutive delimiters here when using RegExp split, so
|
||||
// we have to string-based splitting instead and try to figure out the delimiting chars
|
||||
|
||||
var lineStarts = ts.getLineStarts(inputFile.content);
|
||||
var lineStarts = ts.computeLineStarts(inputFile.content);
|
||||
var lines = inputFile.content.split('\n');
|
||||
lines.forEach((line, lineIndex) => {
|
||||
if (line.length > 0 && line.charAt(line.length - 1) === '\r') {
|
||||
@@ -1002,8 +1005,12 @@ module Harness {
|
||||
assert.equal(markedErrorCount, fileErrors.length, 'count of errors in ' + inputFile.unitName);
|
||||
});
|
||||
|
||||
var numLibraryDiagnostics = ts.countWhere(diagnostics, diagnostic => {
|
||||
return diagnostic.filename && isLibraryFile(diagnostic.filename);
|
||||
});
|
||||
|
||||
// Verify we didn't miss any errors in total
|
||||
assert.equal(totalErrorsReported, diagnostics.length, 'total number of errors');
|
||||
assert.equal(totalErrorsReported + numLibraryDiagnostics, diagnostics.length, 'total number of errors');
|
||||
|
||||
return minimalDiagnosticsToString(diagnostics) +
|
||||
sys.newLine + sys.newLine + outputLines.join('\r\n');
|
||||
@@ -1143,7 +1150,7 @@ module Harness {
|
||||
var optionRegex = /^[\/]{2}\s*@(\w+)\s*:\s*(\S*)/gm; // multiple matches on multiple lines
|
||||
|
||||
// List of allowed metadata names
|
||||
var fileMetadataNames = ["filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outdir", "noimplicitany", "noresolve", "newline", "newlines", "emitbom", "errortruncation", "usecasesensitivefilenames", "preserveconstenums"];
|
||||
var fileMetadataNames = ["filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outdir", "noemitonerror","noimplicitany", "noresolve", "newline", "newlines", "emitbom", "errortruncation", "usecasesensitivefilenames", "preserveconstenums"];
|
||||
|
||||
function extractCompilerSettings(content: string): CompilerSetting[] {
|
||||
|
||||
@@ -1162,7 +1169,7 @@ module Harness {
|
||||
var settings = extractCompilerSettings(code);
|
||||
|
||||
// List of all the subfiles we've parsed out
|
||||
var files: TestUnitData[] = [];
|
||||
var testUnitData: TestUnitData[] = [];
|
||||
|
||||
var lines = Utils.splitContentByNewlines(code);
|
||||
|
||||
@@ -1198,7 +1205,7 @@ module Harness {
|
||||
originalFilePath: fileName,
|
||||
references: refs
|
||||
};
|
||||
files.push(newTestFile);
|
||||
testUnitData.push(newTestFile);
|
||||
|
||||
// Reset local data
|
||||
currentFileContent = null;
|
||||
@@ -1223,7 +1230,7 @@ module Harness {
|
||||
}
|
||||
|
||||
// normalize the fileName for the single file case
|
||||
currentFileName = files.length > 0 ? currentFileName : Path.getFileName(fileName);
|
||||
currentFileName = testUnitData.length > 0 ? currentFileName : Path.getFileName(fileName);
|
||||
|
||||
// EOF, push whatever remains
|
||||
var newTestFile2 = {
|
||||
@@ -1233,9 +1240,9 @@ module Harness {
|
||||
originalFilePath: fileName,
|
||||
references: refs
|
||||
};
|
||||
files.push(newTestFile2);
|
||||
testUnitData.push(newTestFile2);
|
||||
|
||||
return { settings: settings, testUnitData: files };
|
||||
return { settings, testUnitData };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1331,7 +1338,7 @@ module Harness {
|
||||
actual = actual.replace(/\r\n?/g, '\n');
|
||||
}
|
||||
|
||||
return { expected: expected, actual: actual };
|
||||
return { expected, actual };
|
||||
}
|
||||
|
||||
function writeComparison(expected: string, actual: string, relativeFilename: string, actualFilename: string, descriptionForDescribe: string) {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
module Harness.LanguageService {
|
||||
export class ScriptInfo {
|
||||
public version: number = 1;
|
||||
public editRanges: { length: number; textChangeRange: TypeScript.TextChangeRange; }[] = [];
|
||||
public lineMap: TypeScript.LineMap = null;
|
||||
public editRanges: { length: number; textChangeRange: ts.TextChangeRange; }[] = [];
|
||||
public lineMap: number[] = null;
|
||||
|
||||
constructor(public fileName: string, public content: string, public isOpen = true) {
|
||||
this.setContent(content);
|
||||
@@ -13,7 +13,7 @@ module Harness.LanguageService {
|
||||
|
||||
private setContent(content: string): void {
|
||||
this.content = content;
|
||||
this.lineMap = TypeScript.LineMap1.fromString(content);
|
||||
this.lineMap = ts.computeLineStarts(content);
|
||||
}
|
||||
|
||||
public updateContent(content: string): void {
|
||||
@@ -32,30 +32,30 @@ module Harness.LanguageService {
|
||||
// Store edit range + new length of script
|
||||
this.editRanges.push({
|
||||
length: this.content.length,
|
||||
textChangeRange: new TypeScript.TextChangeRange(
|
||||
TypeScript.TextSpan.fromBounds(minChar, limChar), newText.length)
|
||||
textChangeRange: new ts.TextChangeRange(
|
||||
ts.TextSpan.fromBounds(minChar, limChar), newText.length)
|
||||
});
|
||||
|
||||
// Update version #
|
||||
this.version++;
|
||||
}
|
||||
|
||||
public getTextChangeRangeBetweenVersions(startVersion: number, endVersion: number): TypeScript.TextChangeRange {
|
||||
public getTextChangeRangeBetweenVersions(startVersion: number, endVersion: number): ts.TextChangeRange {
|
||||
if (startVersion === endVersion) {
|
||||
// No edits!
|
||||
return TypeScript.TextChangeRange.unchanged;
|
||||
return ts.TextChangeRange.unchanged;
|
||||
}
|
||||
|
||||
var initialEditRangeIndex = this.editRanges.length - (this.version - startVersion);
|
||||
var lastEditRangeIndex = this.editRanges.length - (this.version - endVersion);
|
||||
|
||||
var entries = this.editRanges.slice(initialEditRangeIndex, lastEditRangeIndex);
|
||||
return TypeScript.TextChangeRange.collapseChangesAcrossMultipleVersions(entries.map(e => e.textChangeRange));
|
||||
return ts.TextChangeRange.collapseChangesAcrossMultipleVersions(entries.map(e => e.textChangeRange));
|
||||
}
|
||||
}
|
||||
|
||||
class ScriptSnapshotShim implements ts.ScriptSnapshotShim {
|
||||
private lineMap: TypeScript.LineMap = null;
|
||||
private lineMap: number[] = null;
|
||||
private textSnapshot: string;
|
||||
private version: number;
|
||||
|
||||
@@ -74,10 +74,10 @@ module Harness.LanguageService {
|
||||
|
||||
public getLineStartPositions(): string {
|
||||
if (this.lineMap === null) {
|
||||
this.lineMap = TypeScript.LineMap1.fromString(this.textSnapshot);
|
||||
this.lineMap = ts.computeLineStarts(this.textSnapshot);
|
||||
}
|
||||
|
||||
return JSON.stringify(this.lineMap.lineStarts());
|
||||
return JSON.stringify(this.lineMap);
|
||||
}
|
||||
|
||||
public getChangeRange(oldScript: ts.ScriptSnapshotShim): string {
|
||||
@@ -108,7 +108,7 @@ module Harness.LanguageService {
|
||||
public acquireDocument(
|
||||
fileName: string,
|
||||
compilationSettings: ts.CompilerOptions,
|
||||
scriptSnapshot: TypeScript.IScriptSnapshot,
|
||||
scriptSnapshot: ts.IScriptSnapshot,
|
||||
version: string,
|
||||
isOpen: boolean): ts.SourceFile {
|
||||
return ts.createSourceFile(fileName, scriptSnapshot.getText(0, scriptSnapshot.getLength()), compilationSettings.target, version, isOpen);
|
||||
@@ -118,10 +118,10 @@ module Harness.LanguageService {
|
||||
document: ts.SourceFile,
|
||||
fileName: string,
|
||||
compilationSettings: ts.CompilerOptions,
|
||||
scriptSnapshot: TypeScript.IScriptSnapshot,
|
||||
scriptSnapshot: ts.IScriptSnapshot,
|
||||
version: string,
|
||||
isOpen: boolean,
|
||||
textChangeRange: TypeScript.TextChangeRange
|
||||
textChangeRange: ts.TextChangeRange
|
||||
): ts.SourceFile {
|
||||
return document.update(scriptSnapshot, version, isOpen, textChangeRange);
|
||||
}
|
||||
@@ -263,13 +263,13 @@ module Harness.LanguageService {
|
||||
}
|
||||
|
||||
/** Parse file given its source text */
|
||||
public parseSourceText(fileName: string, sourceText: TypeScript.IScriptSnapshot): TypeScript.SourceUnitSyntax {
|
||||
return TypeScript.Parser.parse(fileName, TypeScript.SimpleText.fromScriptSnapshot(sourceText), ts.ScriptTarget.Latest, TypeScript.isDTSFile(fileName)).sourceUnit();
|
||||
public parseSourceText(fileName: string, sourceText: ts.IScriptSnapshot): ts.SourceFile {
|
||||
return ts.createSourceFile(fileName, sourceText.getText(0, sourceText.getLength()), ts.ScriptTarget.Latest, "1", true);
|
||||
}
|
||||
|
||||
/** Parse a file on disk given its fileName */
|
||||
public parseFile(fileName: string) {
|
||||
var sourceText = TypeScript.ScriptSnapshot.fromString(Harness.IO.readFile(fileName));
|
||||
var sourceText = ts.ScriptSnapshot.fromString(Harness.IO.readFile(fileName));
|
||||
return this.parseSourceText(fileName, sourceText);
|
||||
}
|
||||
|
||||
@@ -283,22 +283,22 @@ module Harness.LanguageService {
|
||||
assert.isTrue(line >= 1);
|
||||
assert.isTrue(col >= 1);
|
||||
|
||||
return script.lineMap.getPosition(line - 1, col - 1);
|
||||
return ts.getPositionFromLineAndCharacter(script.lineMap, line, col);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param line 0 based index
|
||||
* @param col 0 based index
|
||||
*/
|
||||
public positionToZeroBasedLineCol(fileName: string, position: number): TypeScript.ILineAndCharacter {
|
||||
public positionToZeroBasedLineCol(fileName: string, position: number): ts.LineAndCharacter {
|
||||
var script: ScriptInfo = this.fileNameToScript[fileName];
|
||||
assert.isNotNull(script);
|
||||
|
||||
var result = script.lineMap.getLineAndCharacterFromPosition(position);
|
||||
var result = ts.getLineAndCharacterOfPosition(script.lineMap, position);
|
||||
|
||||
assert.isTrue(result.line() >= 0);
|
||||
assert.isTrue(result.character() >= 0);
|
||||
return { line: result.line(), character: result.character() };
|
||||
assert.isTrue(result.line >= 1);
|
||||
assert.isTrue(result.character >= 1);
|
||||
return { line: result.line - 1, character: result.character - 1 };
|
||||
}
|
||||
|
||||
/** Verify that applying edits to sourceFileName result in the content of the file baselineFileName */
|
||||
|
||||
@@ -132,8 +132,8 @@ class ProjectRunner extends RunnerBase {
|
||||
if (!errors.length) {
|
||||
var checker = program.getTypeChecker(/*fullTypeCheck*/ true);
|
||||
errors = checker.getDiagnostics();
|
||||
var emitResult = checker.emitFiles();
|
||||
errors = ts.concatenate(errors, emitResult.errors);
|
||||
var emitResult = checker.invokeEmitter();
|
||||
errors = ts.concatenate(errors, emitResult.diagnostics);
|
||||
sourceMapData = emitResult.sourceMaps;
|
||||
|
||||
// Clean up source map data that will be used in baselining
|
||||
@@ -149,10 +149,10 @@ class ProjectRunner extends RunnerBase {
|
||||
}
|
||||
|
||||
return {
|
||||
moduleKind: moduleKind,
|
||||
program: program,
|
||||
errors: errors,
|
||||
sourceMapData: sourceMapData
|
||||
moduleKind,
|
||||
program,
|
||||
errors,
|
||||
sourceMapData
|
||||
};
|
||||
|
||||
function createCompilerOptions(): ts.CompilerOptions {
|
||||
@@ -185,10 +185,10 @@ class ProjectRunner extends RunnerBase {
|
||||
|
||||
function createCompilerHost(): ts.CompilerHost {
|
||||
return {
|
||||
getSourceFile: getSourceFile,
|
||||
getSourceFile,
|
||||
getDefaultLibFilename: () => "lib.d.ts",
|
||||
writeFile: writeFile,
|
||||
getCurrentDirectory: getCurrentDirectory,
|
||||
writeFile,
|
||||
getCurrentDirectory,
|
||||
getCanonicalFileName: Harness.Compiler.getCanonicalFileName,
|
||||
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
|
||||
getNewLine: () => sys.newLine
|
||||
@@ -203,12 +203,12 @@ class ProjectRunner extends RunnerBase {
|
||||
|
||||
var projectCompilerResult = compileProjectFiles(moduleKind, () => testCase.inputFiles, getSourceFileText, writeFile);
|
||||
return {
|
||||
moduleKind: moduleKind,
|
||||
moduleKind,
|
||||
program: projectCompilerResult.program,
|
||||
sourceMapData: projectCompilerResult.sourceMapData,
|
||||
outputFiles: outputFiles,
|
||||
outputFiles,
|
||||
errors: projectCompilerResult.errors,
|
||||
nonSubfolderDiskFiles: nonSubfolderDiskFiles,
|
||||
nonSubfolderDiskFiles,
|
||||
};
|
||||
|
||||
function getSourceFileText(filename: string): string {
|
||||
|
||||
@@ -117,14 +117,14 @@ module RWC {
|
||||
});
|
||||
|
||||
function getHarnessCompilerInputUnit(fileName: string) {
|
||||
var resolvedPath = ts.normalizeSlashes(sys.resolvePath(fileName));
|
||||
var unitName = ts.normalizeSlashes(sys.resolvePath(fileName));
|
||||
try {
|
||||
var content = sys.readFile(resolvedPath);
|
||||
var content = sys.readFile(unitName);
|
||||
}
|
||||
catch (e) {
|
||||
// Leave content undefined.
|
||||
}
|
||||
return { unitName: resolvedPath, content: content };
|
||||
return { unitName, content };
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -223,7 +223,7 @@ module Harness.SourceMapRecoder {
|
||||
sourceMapNames = sourceMapData.sourceMapNames;
|
||||
|
||||
jsFile = currentJsFile;
|
||||
jsLineMap = ts.getLineStarts(jsFile.code);
|
||||
jsLineMap = ts.computeLineStarts(jsFile.code);
|
||||
|
||||
spansOnSingleLine = [];
|
||||
prevWrittenSourcePos = 0;
|
||||
@@ -294,7 +294,7 @@ module Harness.SourceMapRecoder {
|
||||
sourceMapRecoder.WriteLine("sourceFile:" + sourceMapSources[spansOnSingleLine[0].sourceMapSpan.sourceIndex]);
|
||||
sourceMapRecoder.WriteLine("-------------------------------------------------------------------");
|
||||
|
||||
tsLineMap = ts.getLineStarts(newSourceFileCode);
|
||||
tsLineMap = ts.computeLineStarts(newSourceFileCode);
|
||||
tsCode = newSourceFileCode;
|
||||
prevWrittenSourcePos = 0;
|
||||
}
|
||||
@@ -390,7 +390,7 @@ module Harness.SourceMapRecoder {
|
||||
}
|
||||
}
|
||||
|
||||
var tsCodeLineMap = ts.getLineStarts(sourceText);
|
||||
var tsCodeLineMap = ts.computeLineStarts(sourceText);
|
||||
for (var i = 0; i < tsCodeLineMap.length; i++) {
|
||||
writeSourceMapIndent(prevEmittedCol, i == 0 ? markerIds[index] : " >");
|
||||
sourceMapRecoder.Write(getTextOfLine(i, tsCodeLineMap, sourceText));
|
||||
|
||||
+18
-18
@@ -38,25 +38,25 @@ module ts.BreakpointResolver {
|
||||
return spanInNode(tokenAtLocation);
|
||||
|
||||
function textSpan(startNode: Node, endNode?: Node) {
|
||||
return TypeScript.TextSpan.fromBounds(startNode.getStart(), (endNode || startNode).getEnd());
|
||||
return TextSpan.fromBounds(startNode.getStart(), (endNode || startNode).getEnd());
|
||||
}
|
||||
|
||||
function spanInNodeIfStartsOnSameLine(node: Node, otherwiseOnNode?: Node): TypeScript.TextSpan {
|
||||
function spanInNodeIfStartsOnSameLine(node: Node, otherwiseOnNode?: Node): TextSpan {
|
||||
if (node && lineOfPosition === sourceFile.getLineAndCharacterFromPosition(node.getStart()).line) {
|
||||
return spanInNode(node);
|
||||
}
|
||||
return spanInNode(otherwiseOnNode);
|
||||
}
|
||||
|
||||
function spanInPreviousNode(node: Node): TypeScript.TextSpan {
|
||||
function spanInPreviousNode(node: Node): TextSpan {
|
||||
return spanInNode(findPrecedingToken(node.pos, sourceFile));
|
||||
}
|
||||
|
||||
function spanInNextNode(node: Node): TypeScript.TextSpan {
|
||||
function spanInNextNode(node: Node): TextSpan {
|
||||
return spanInNode(findNextToken(node, node.parent));
|
||||
}
|
||||
|
||||
function spanInNode(node: Node): TypeScript.TextSpan {
|
||||
function spanInNode(node: Node): TextSpan {
|
||||
if (node) {
|
||||
if (isExpression(node)) {
|
||||
if (node.parent.kind === SyntaxKind.DoStatement) {
|
||||
@@ -256,7 +256,7 @@ module ts.BreakpointResolver {
|
||||
}
|
||||
}
|
||||
|
||||
function spanInVariableDeclaration(variableDeclaration: VariableDeclaration): TypeScript.TextSpan {
|
||||
function spanInVariableDeclaration(variableDeclaration: VariableDeclaration): TextSpan {
|
||||
// If declaration of for in statement, just set the span in parent
|
||||
if (variableDeclaration.parent.kind === SyntaxKind.ForInStatement) {
|
||||
return spanInNode(variableDeclaration.parent);
|
||||
@@ -301,7 +301,7 @@ module ts.BreakpointResolver {
|
||||
!!(parameter.flags & NodeFlags.Public) || !!(parameter.flags & NodeFlags.Private);
|
||||
}
|
||||
|
||||
function spanInParameterDeclaration(parameter: ParameterDeclaration): TypeScript.TextSpan {
|
||||
function spanInParameterDeclaration(parameter: ParameterDeclaration): TextSpan {
|
||||
if (canHaveSpanInParameterDeclaration(parameter)) {
|
||||
return textSpan(parameter);
|
||||
}
|
||||
@@ -324,7 +324,7 @@ module ts.BreakpointResolver {
|
||||
(functionDeclaration.parent.kind === SyntaxKind.ClassDeclaration && functionDeclaration.kind !== SyntaxKind.Constructor);
|
||||
}
|
||||
|
||||
function spanInFunctionDeclaration(functionDeclaration: FunctionLikeDeclaration): TypeScript.TextSpan {
|
||||
function spanInFunctionDeclaration(functionDeclaration: FunctionLikeDeclaration): TextSpan {
|
||||
// No breakpoints in the function signature
|
||||
if (!functionDeclaration.body) {
|
||||
return undefined;
|
||||
@@ -339,7 +339,7 @@ module ts.BreakpointResolver {
|
||||
return spanInNode(functionDeclaration.body);
|
||||
}
|
||||
|
||||
function spanInFunctionBlock(block: Block): TypeScript.TextSpan {
|
||||
function spanInFunctionBlock(block: Block): TextSpan {
|
||||
var nodeForSpanInBlock = block.statements.length ? block.statements[0] : block.getLastToken();
|
||||
if (canFunctionHaveSpanInWholeDeclaration(<FunctionLikeDeclaration>block.parent)) {
|
||||
return spanInNodeIfStartsOnSameLine(block.parent, nodeForSpanInBlock);
|
||||
@@ -348,7 +348,7 @@ module ts.BreakpointResolver {
|
||||
return spanInNode(nodeForSpanInBlock);
|
||||
}
|
||||
|
||||
function spanInBlock(block: Block): TypeScript.TextSpan {
|
||||
function spanInBlock(block: Block): TextSpan {
|
||||
switch (block.parent.kind) {
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
if (getModuleInstanceState(block.parent) !== ModuleInstanceState.Instantiated) {
|
||||
@@ -370,7 +370,7 @@ module ts.BreakpointResolver {
|
||||
return spanInNode(block.statements[0]);
|
||||
}
|
||||
|
||||
function spanInForStatement(forStatement: ForStatement): TypeScript.TextSpan {
|
||||
function spanInForStatement(forStatement: ForStatement): TextSpan {
|
||||
if (forStatement.declarations) {
|
||||
return spanInNode(forStatement.declarations[0]);
|
||||
}
|
||||
@@ -386,7 +386,7 @@ module ts.BreakpointResolver {
|
||||
}
|
||||
|
||||
// Tokens:
|
||||
function spanInOpenBraceToken(node: Node): TypeScript.TextSpan {
|
||||
function spanInOpenBraceToken(node: Node): TextSpan {
|
||||
switch (node.parent.kind) {
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
var enumDeclaration = <EnumDeclaration>node.parent;
|
||||
@@ -404,7 +404,7 @@ module ts.BreakpointResolver {
|
||||
return spanInNode(node.parent);
|
||||
}
|
||||
|
||||
function spanInCloseBraceToken(node: Node): TypeScript.TextSpan {
|
||||
function spanInCloseBraceToken(node: Node): TextSpan {
|
||||
switch (node.parent.kind) {
|
||||
case SyntaxKind.ModuleBlock:
|
||||
// If this is not instantiated module block no bp span
|
||||
@@ -439,7 +439,7 @@ module ts.BreakpointResolver {
|
||||
}
|
||||
}
|
||||
|
||||
function spanInOpenParenToken(node: Node): TypeScript.TextSpan {
|
||||
function spanInOpenParenToken(node: Node): TextSpan {
|
||||
if (node.parent.kind === SyntaxKind.DoStatement) {
|
||||
// Go to while keyword and do action instead
|
||||
return spanInPreviousNode(node);
|
||||
@@ -449,7 +449,7 @@ module ts.BreakpointResolver {
|
||||
return spanInNode(node.parent);
|
||||
}
|
||||
|
||||
function spanInCloseParenToken(node: Node): TypeScript.TextSpan {
|
||||
function spanInCloseParenToken(node: Node): TextSpan {
|
||||
// Is this close paren token of parameter list, set span in previous token
|
||||
switch (node.parent.kind) {
|
||||
case SyntaxKind.FunctionExpression:
|
||||
@@ -473,7 +473,7 @@ module ts.BreakpointResolver {
|
||||
return spanInNode(node.parent);
|
||||
}
|
||||
|
||||
function spanInColonToken(node: Node): TypeScript.TextSpan {
|
||||
function spanInColonToken(node: Node): TextSpan {
|
||||
// Is this : specifying return annotation of the function declaration
|
||||
if (isAnyFunction(node.parent) || node.parent.kind === SyntaxKind.PropertyAssignment) {
|
||||
return spanInPreviousNode(node);
|
||||
@@ -482,7 +482,7 @@ module ts.BreakpointResolver {
|
||||
return spanInNode(node.parent);
|
||||
}
|
||||
|
||||
function spanInGreaterThanOrLessThanToken(node: Node): TypeScript.TextSpan {
|
||||
function spanInGreaterThanOrLessThanToken(node: Node): TextSpan {
|
||||
if (node.parent.kind === SyntaxKind.TypeAssertion) {
|
||||
return spanInNode((<TypeAssertion>node.parent).operand);
|
||||
}
|
||||
@@ -490,7 +490,7 @@ module ts.BreakpointResolver {
|
||||
return spanInNode(node.parent);
|
||||
}
|
||||
|
||||
function spanInWhileKeyword(node: Node): TypeScript.TextSpan {
|
||||
function spanInWhileKeyword(node: Node): TextSpan {
|
||||
if (node.parent.kind === SyntaxKind.DoStatement) {
|
||||
// Set span on while expression
|
||||
return textSpan(node, findNextToken((<DoStatement>node.parent).expression, node.parent));
|
||||
|
||||
@@ -0,0 +1,953 @@
|
||||
///<reference path='services.ts' />
|
||||
///<reference path='formatting\indentation.ts' />
|
||||
///<reference path='formatting\formattingScanner.ts' />
|
||||
///<reference path='formatting\rulesProvider.ts' />
|
||||
|
||||
module ts.formatting {
|
||||
|
||||
export interface TextRangeWithKind extends TextRange {
|
||||
kind: SyntaxKind;
|
||||
}
|
||||
|
||||
export interface TokenInfo {
|
||||
leadingTrivia: TextRangeWithKind[];
|
||||
token: TextRangeWithKind;
|
||||
trailingTrivia: TextRangeWithKind[];
|
||||
}
|
||||
|
||||
const enum Constants {
|
||||
Unknown = -1
|
||||
}
|
||||
|
||||
/*
|
||||
* Indentation for the scope that can be dynamically recomputed.
|
||||
* i.e
|
||||
* while(true)
|
||||
* { var x;
|
||||
* }
|
||||
* Normally indentation is applied only to the first token in line so at glance 'var' should not be touched.
|
||||
* However if some format rule adds new line between '}' and 'var' 'var' will become
|
||||
* the first token in line so it should be indented
|
||||
*/
|
||||
interface DynamicIndentation {
|
||||
getIndentationForToken(tokenLine: number, tokenKind: SyntaxKind): number;
|
||||
getIndentationForComment(owningToken: SyntaxKind): number;
|
||||
/**
|
||||
* Indentation for open and close tokens of the node if it is block or another node that needs special indentation
|
||||
* ... {
|
||||
* .........<child>
|
||||
* ....}
|
||||
* ____ - indentation
|
||||
* ____ - delta
|
||||
**/
|
||||
getIndentation(): number;
|
||||
/**
|
||||
* Prefered relative indentation for child nodes.
|
||||
* Delta is used to carry the indentation info
|
||||
* foo(bar({
|
||||
* $
|
||||
* }))
|
||||
* Both 'foo', 'bar' introduce new indentation with delta = 4, but total indentation in $ is not 8.
|
||||
* foo: { indentation: 0, delta: 4 }
|
||||
* bar: { indentation: foo.indentation + foo.delta = 4, delta: 4} however 'foo' and 'bar' are on the same line
|
||||
* so bar inherits indentation from foo and bar.delta will be 4
|
||||
*
|
||||
*/
|
||||
getDelta(): number;
|
||||
/**
|
||||
* Formatter calls this function when rule adds or deletes new lines from the text
|
||||
* so indentation scope can adjust values of indentation and delta.
|
||||
*/
|
||||
recomputeIndentation(lineAddedByFormatting: boolean): void;
|
||||
}
|
||||
|
||||
interface Indentation {
|
||||
indentation: number;
|
||||
delta: number
|
||||
}
|
||||
|
||||
export function formatOnEnter(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
|
||||
var line = sourceFile.getLineAndCharacterFromPosition(position).line;
|
||||
Debug.assert(line >= 2);
|
||||
// get the span for the previous\current line
|
||||
var span = {
|
||||
// get start position for the previous line
|
||||
pos: getStartPositionOfLine(line - 1, sourceFile),
|
||||
// get end position for the current line (end value is exclusive so add 1 to the result)
|
||||
end: getEndLinePosition(line, sourceFile) + 1
|
||||
}
|
||||
return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnEnter);
|
||||
}
|
||||
|
||||
export function formatOnSemicolon(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
|
||||
return formatOutermostParent(position, SyntaxKind.SemicolonToken, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnSemicolon);
|
||||
}
|
||||
|
||||
export function formatOnClosingCurly(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
|
||||
return formatOutermostParent(position, SyntaxKind.CloseBraceToken, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnClosingCurlyBrace);
|
||||
}
|
||||
|
||||
export function formatDocument(sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
|
||||
var span = {
|
||||
pos: 0,
|
||||
end: sourceFile.text.length
|
||||
};
|
||||
return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatDocument);
|
||||
}
|
||||
|
||||
export function formatSelection(start: number, end: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeOptions): TextChange[] {
|
||||
// format from the beginning of the line
|
||||
var span = {
|
||||
pos: getStartLinePositionForPosition(start, sourceFile),
|
||||
end: end
|
||||
};
|
||||
return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatSelection);
|
||||
}
|
||||
|
||||
function formatOutermostParent(position: number, expectedLastToken: SyntaxKind, sourceFile: SourceFile, options: FormatCodeOptions, rulesProvider: RulesProvider, requestKind: FormattingRequestKind): TextChange[] {
|
||||
var parent = findOutermostParent(position, expectedLastToken, sourceFile);
|
||||
if (!parent) {
|
||||
return [];
|
||||
}
|
||||
var span = {
|
||||
pos: getStartLinePositionForPosition(parent.getStart(sourceFile), sourceFile),
|
||||
end: parent.end
|
||||
};
|
||||
return formatSpan(span, sourceFile, options, rulesProvider, requestKind);
|
||||
}
|
||||
|
||||
function findOutermostParent(position: number, expectedTokenKind: SyntaxKind, sourceFile: SourceFile): Node {
|
||||
var precedingToken = findPrecedingToken(position, sourceFile);
|
||||
if (!precedingToken || precedingToken.kind !== expectedTokenKind) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// walk up and search for the parent node that ends at the same position with precedingToken.
|
||||
// for cases like this
|
||||
//
|
||||
// var x = 1;
|
||||
// while (true) {
|
||||
// }
|
||||
// after typing close curly in while statement we want to reformat just the while statement.
|
||||
// However if we just walk upwards searching for the parent that has the same end value -
|
||||
// we'll end up with the whole source file. isListElement allows to stop on the list element level
|
||||
var current = precedingToken;
|
||||
while (current &&
|
||||
current.parent &&
|
||||
current.parent.end === precedingToken.end &&
|
||||
!isListElement(current.parent, current)) {
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
// Returns true if node is a element in some list in parent
|
||||
// i.e. parent is class declaration with the list of members and node is one of members.
|
||||
function isListElement(parent: Node, node: Node): boolean {
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
return rangeContainsRange((<InterfaceDeclaration>parent).members, node);
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
var body = (<ModuleDeclaration>parent).body;
|
||||
return body && body.kind === SyntaxKind.Block && rangeContainsRange((<Block>body).statements, node);
|
||||
case SyntaxKind.SourceFile:
|
||||
case SyntaxKind.Block:
|
||||
case SyntaxKind.TryBlock:
|
||||
case SyntaxKind.CatchBlock:
|
||||
case SyntaxKind.FinallyBlock:
|
||||
case SyntaxKind.ModuleBlock:
|
||||
return rangeContainsRange((<Block>parent).statements, node)
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** find node that fully contains given text range */
|
||||
function findEnclosingNode(range: TextRange, sourceFile: SourceFile): Node {
|
||||
return find(sourceFile);
|
||||
|
||||
function find(n: Node): Node {
|
||||
var candidate = forEachChild(n, c => startEndContainsRange(c.getStart(sourceFile), c.end, range) && c);
|
||||
if (candidate) {
|
||||
var result = find(candidate);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
/** formatting is not applied to ranges that contain parse errors.
|
||||
* This function will return a predicate that for a given text range will tell
|
||||
* if there are any parse errors that overlap with the range.
|
||||
*/
|
||||
function prepareRangeContainsErrorFunction(errors: Diagnostic[], originalRange: TextRange): (r: TextRange) => boolean {
|
||||
if (!errors.length) {
|
||||
return rangeHasNoErrors;
|
||||
}
|
||||
|
||||
// pick only errors that fall in range
|
||||
var sorted = errors
|
||||
.filter(d => d.isParseError && rangeOverlapsWithStartEnd(originalRange, d.start, d.start + d.length))
|
||||
.sort((e1, e2) => e1.start - e2.start);
|
||||
|
||||
if (!sorted.length) {
|
||||
return rangeHasNoErrors;
|
||||
}
|
||||
|
||||
var index = 0;
|
||||
|
||||
return r => {
|
||||
// in current implementation sequence of arguments [r1, r2...] is monotonically increasing.
|
||||
// 'index' tracks the index of the most recent error that was checked.
|
||||
while (true) {
|
||||
if (index >= sorted.length) {
|
||||
// all errors in the range were already checked -> no error in specified range
|
||||
return false;
|
||||
}
|
||||
|
||||
var error = sorted[index];
|
||||
if (r.end <= error.start) {
|
||||
// specified range ends before the error refered by 'index' - no error in range
|
||||
return false;
|
||||
}
|
||||
|
||||
if (startEndOverlapsWithStartEnd(r.pos, r.end, error.start, error.start + error.length)) {
|
||||
// specified range overlaps with error range
|
||||
return true;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
};
|
||||
|
||||
function rangeHasNoErrors(r: TextRange): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start of the original range might fall inside the comment - scanner will not yield appropriate results
|
||||
* This function will look for token that is located before the start of target range
|
||||
* and return its end as start position for the scanner.
|
||||
*/
|
||||
function getScanStartPosition(enclosingNode: Node, originalRange: TextRange, sourceFile: SourceFile): number {
|
||||
var start = enclosingNode.getStart(sourceFile);
|
||||
if (start === originalRange.pos && enclosingNode.end === originalRange.end) {
|
||||
return start;
|
||||
}
|
||||
|
||||
var precedingToken = findPrecedingToken(originalRange.pos, sourceFile);
|
||||
// no preceding token found - start from the beginning of enclosing node
|
||||
return precedingToken ? precedingToken.end : enclosingNode.pos;
|
||||
}
|
||||
|
||||
function formatSpan(originalRange: TextRange,
|
||||
sourceFile: SourceFile,
|
||||
options: FormatCodeOptions,
|
||||
rulesProvider: RulesProvider,
|
||||
requestKind: FormattingRequestKind): TextChange[] {
|
||||
|
||||
var rangeContainsError = prepareRangeContainsErrorFunction(sourceFile.syntacticErrors, originalRange);
|
||||
|
||||
// formatting context is used by rules provider
|
||||
var formattingContext = new FormattingContext(sourceFile, requestKind);
|
||||
|
||||
// find the smallest node that fully wraps the range and compute the initial indentation for the node
|
||||
var enclosingNode = findEnclosingNode(originalRange, sourceFile);
|
||||
|
||||
var formattingScanner = getFormattingScanner(sourceFile, getScanStartPosition(enclosingNode, originalRange, sourceFile), originalRange.end);
|
||||
|
||||
var initialIndentation = SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, options);
|
||||
|
||||
var previousRangeHasError: boolean;
|
||||
var previousRange: TextRangeWithKind;
|
||||
var previousParent: Node;
|
||||
var previousRangeStartLine: number;
|
||||
|
||||
var edits: TextChange[] = [];
|
||||
|
||||
formattingScanner.advance();
|
||||
|
||||
if (formattingScanner.isOnToken()) {
|
||||
var startLine = sourceFile.getLineAndCharacterFromPosition(enclosingNode.getStart(sourceFile)).line;
|
||||
var delta = SmartIndenter.shouldIndentChildNode(enclosingNode.kind, SyntaxKind.Unknown) ? options.IndentSize : 0;
|
||||
processNode(enclosingNode, enclosingNode, startLine, initialIndentation, delta);
|
||||
}
|
||||
|
||||
formattingScanner.close();
|
||||
|
||||
return edits;
|
||||
|
||||
// local functions
|
||||
|
||||
/** Tries to compute the indentation for a list element.
|
||||
* If list element is not in range then
|
||||
* function will pick its actual indentation
|
||||
* so it can be pushed downstream as inherited indentation.
|
||||
* If list element is in the range - its indentation will be equal
|
||||
* to inherited indentation from its predecessors.
|
||||
*/
|
||||
function tryComputeIndentationForListItem(startPos: number,
|
||||
endPos: number,
|
||||
parentStartLine: number,
|
||||
range: TextRange,
|
||||
inheritedIndentation: number): number {
|
||||
|
||||
if (rangeOverlapsWithStartEnd(range, startPos, endPos)) {
|
||||
if (inheritedIndentation !== Constants.Unknown) {
|
||||
return inheritedIndentation;
|
||||
}
|
||||
}
|
||||
else {
|
||||
var startLine = sourceFile.getLineAndCharacterFromPosition(startPos).line;
|
||||
var startLinePosition = getStartLinePositionForPosition(startPos, sourceFile);
|
||||
var column = SmartIndenter.findFirstNonWhitespaceColumn(startLinePosition, startPos, sourceFile, options);
|
||||
if (startLine !== parentStartLine || startPos === column) {
|
||||
return column
|
||||
}
|
||||
}
|
||||
|
||||
return Constants.Unknown;
|
||||
}
|
||||
|
||||
function computeIndentation(
|
||||
node: TextRangeWithKind,
|
||||
startLine: number,
|
||||
inheritedIndentation: number,
|
||||
parent: Node,
|
||||
parentDynamicIndentation: DynamicIndentation,
|
||||
effectiveParentStartLine: number): Indentation {
|
||||
|
||||
var indentation = inheritedIndentation;
|
||||
if (indentation === Constants.Unknown) {
|
||||
if (isSomeBlock(node.kind)) {
|
||||
// blocks should be indented in
|
||||
// - other blocks
|
||||
// - source file
|
||||
// - switch\default clauses
|
||||
if (isSomeBlock(parent.kind) ||
|
||||
parent.kind === SyntaxKind.SourceFile ||
|
||||
parent.kind === SyntaxKind.CaseClause ||
|
||||
parent.kind === SyntaxKind.DefaultClause) {
|
||||
|
||||
indentation = parentDynamicIndentation.getIndentation() + parentDynamicIndentation.getDelta();
|
||||
}
|
||||
else {
|
||||
indentation = parentDynamicIndentation.getIndentation();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (SmartIndenter.childStartsOnTheSameLineWithElseInIfStatement(parent, node, startLine, sourceFile)) {
|
||||
indentation = parentDynamicIndentation.getIndentation();
|
||||
}
|
||||
else {
|
||||
indentation = parentDynamicIndentation.getIndentation() + parentDynamicIndentation.getDelta();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var delta = SmartIndenter.shouldIndentChildNode(node.kind, SyntaxKind.Unknown) ? options.IndentSize : 0;
|
||||
|
||||
if (effectiveParentStartLine === startLine) {
|
||||
// if node is located on the same line with the parent
|
||||
// - inherit indentation from the parent
|
||||
// - push children if either parent of node itself has non-zero delta
|
||||
indentation = parentDynamicIndentation.getIndentation();
|
||||
delta = Math.min(options.IndentSize, parentDynamicIndentation.getDelta() + delta);
|
||||
}
|
||||
return {
|
||||
indentation,
|
||||
delta
|
||||
}
|
||||
}
|
||||
|
||||
function getDynamicIndentation(node: Node, nodeStartLine: number, indentation: number, delta: number): DynamicIndentation {
|
||||
return {
|
||||
getIndentationForComment: kind => {
|
||||
switch (kind) {
|
||||
// preceding comment to the token that closes the indentation scope inherits the indentation from the scope
|
||||
// .. {
|
||||
// // comment
|
||||
// }
|
||||
case SyntaxKind.CloseBraceToken:
|
||||
case SyntaxKind.CloseBracketToken:
|
||||
return indentation + delta;
|
||||
}
|
||||
return indentation;
|
||||
},
|
||||
getIndentationForToken: (line, kind) => {
|
||||
switch (kind) {
|
||||
// open and close brace, 'else' and 'while' (in do statement) tokens has indentation of the parent
|
||||
case SyntaxKind.OpenBraceToken:
|
||||
case SyntaxKind.CloseBraceToken:
|
||||
case SyntaxKind.OpenBracketToken:
|
||||
case SyntaxKind.CloseBracketToken:
|
||||
case SyntaxKind.ElseKeyword:
|
||||
case SyntaxKind.WhileKeyword:
|
||||
return indentation;
|
||||
default:
|
||||
// if token line equals to the line of containing node (this is a first token in the node) - use node indentation
|
||||
return nodeStartLine !== line ? indentation + delta : indentation;
|
||||
}
|
||||
},
|
||||
getIndentation: () => indentation,
|
||||
getDelta: () => delta,
|
||||
recomputeIndentation: lineAdded => {
|
||||
if (node.parent && SmartIndenter.shouldIndentChildNode(node.parent.kind, node.kind)) {
|
||||
if (lineAdded) {
|
||||
indentation += options.IndentSize;
|
||||
}
|
||||
else {
|
||||
indentation -= options.IndentSize;
|
||||
}
|
||||
|
||||
if (SmartIndenter.shouldIndentChildNode(node.kind, SyntaxKind.Unknown)) {
|
||||
delta = options.IndentSize;
|
||||
}
|
||||
else {
|
||||
delta = 0;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function processNode(node: Node, contextNode: Node, nodeStartLine: number, indentation: number, delta: number) {
|
||||
if (!rangeOverlapsWithStartEnd(originalRange, node.getStart(sourceFile), node.getEnd())) {
|
||||
return;
|
||||
}
|
||||
|
||||
var nodeDynamicIndentation = getDynamicIndentation(node, nodeStartLine, indentation, delta);
|
||||
|
||||
// a useful observations when tracking context node
|
||||
// /
|
||||
// [a]
|
||||
// / | \
|
||||
// [b] [c] [d]
|
||||
// node 'a' is a context node for nodes 'b', 'c', 'd'
|
||||
// except for the leftmost leaf token in [b] - in this case context node ('e') is located somewhere above 'a'
|
||||
// this rule can be applied recursively to child nodes of 'a'.
|
||||
//
|
||||
// context node is set to parent node value after processing every child node
|
||||
// context node is set to parent of the token after processing every token
|
||||
|
||||
var childContextNode = contextNode;
|
||||
|
||||
// if there are any tokens that logically belong to node and interleave child nodes
|
||||
// such tokens will be consumed in processChildNode for for the child that follows them
|
||||
forEachChild(
|
||||
node,
|
||||
child => {
|
||||
processChildNode(child, /*inheritedIndentation*/ Constants.Unknown, node, nodeDynamicIndentation, nodeStartLine, /*isListElement*/ false)
|
||||
},
|
||||
(nodes: NodeArray<Node>) => {
|
||||
processChildNodes(nodes, node, nodeStartLine, nodeDynamicIndentation);
|
||||
});
|
||||
|
||||
// proceed any tokens in the node that are located after child nodes
|
||||
while (formattingScanner.isOnToken()) {
|
||||
var tokenInfo = formattingScanner.readTokenInfo(node);
|
||||
if (tokenInfo.token.end > node.end) {
|
||||
break;
|
||||
}
|
||||
consumeTokenAndAdvanceScanner(tokenInfo, node, nodeDynamicIndentation);
|
||||
}
|
||||
|
||||
function processChildNode(
|
||||
child: Node,
|
||||
inheritedIndentation: number,
|
||||
parent: Node,
|
||||
parentDynamicIndentation: DynamicIndentation,
|
||||
parentStartLine: number,
|
||||
isListItem: boolean): number {
|
||||
|
||||
var childStartPos = child.getStart(sourceFile);
|
||||
|
||||
var childStart = sourceFile.getLineAndCharacterFromPosition(childStartPos);
|
||||
|
||||
// if child is a list item - try to get its indentation
|
||||
var childIndentationAmount = Constants.Unknown;
|
||||
if (isListItem) {
|
||||
childIndentationAmount = tryComputeIndentationForListItem(childStartPos, child.end, parentStartLine, originalRange, inheritedIndentation);
|
||||
if (childIndentationAmount !== Constants.Unknown) {
|
||||
inheritedIndentation = childIndentationAmount;
|
||||
}
|
||||
}
|
||||
|
||||
// child node is outside the target range - do not dive inside
|
||||
if (!rangeOverlapsWithStartEnd(originalRange, child.pos, child.end)) {
|
||||
return inheritedIndentation;
|
||||
}
|
||||
|
||||
if (child.kind === SyntaxKind.Missing) {
|
||||
return inheritedIndentation;
|
||||
}
|
||||
|
||||
while (formattingScanner.isOnToken()) {
|
||||
// proceed any parent tokens that are located prior to child.getStart()
|
||||
var tokenInfo = formattingScanner.readTokenInfo(node);
|
||||
if (tokenInfo.token.end > childStartPos) {
|
||||
// stop when formatting scanner advances past the beginning of the child
|
||||
break;
|
||||
}
|
||||
|
||||
consumeTokenAndAdvanceScanner(tokenInfo, node, parentDynamicIndentation);
|
||||
}
|
||||
|
||||
if (!formattingScanner.isOnToken()) {
|
||||
return inheritedIndentation;
|
||||
}
|
||||
|
||||
if (isToken(child)) {
|
||||
// if child node is a token, it does not impact indentation, proceed it using parent indentation scope rules
|
||||
var tokenInfo = formattingScanner.readTokenInfo(node);
|
||||
Debug.assert(tokenInfo.token.end === child.end);
|
||||
consumeTokenAndAdvanceScanner(tokenInfo, node, parentDynamicIndentation);
|
||||
return inheritedIndentation;
|
||||
}
|
||||
|
||||
var childIndentation = computeIndentation(child, childStart.line, childIndentationAmount, node, parentDynamicIndentation, parentStartLine);
|
||||
|
||||
processNode(child, childContextNode, childStart.line, childIndentation.indentation, childIndentation.delta);
|
||||
|
||||
childContextNode = node;
|
||||
|
||||
return inheritedIndentation;
|
||||
}
|
||||
|
||||
function processChildNodes(nodes: NodeArray<Node>,
|
||||
parent: Node,
|
||||
parentStartLine: number,
|
||||
parentDynamicIndentation: DynamicIndentation): void {
|
||||
|
||||
var listStartToken = getOpenTokenForList(parent, nodes);
|
||||
var listEndToken = getCloseTokenForOpenToken(listStartToken);
|
||||
|
||||
var listDynamicIndentation = parentDynamicIndentation;
|
||||
var startLine = parentStartLine;
|
||||
|
||||
if (listStartToken !== SyntaxKind.Unknown) {
|
||||
// introduce a new indentation scope for lists (including list start and end tokens)
|
||||
while (formattingScanner.isOnToken()) {
|
||||
var tokenInfo = formattingScanner.readTokenInfo(parent);
|
||||
if (tokenInfo.token.end > nodes.pos) {
|
||||
// stop when formatting scanner moves past the beginning of node list
|
||||
break;
|
||||
}
|
||||
else if (tokenInfo.token.kind === listStartToken) {
|
||||
// consume list start token
|
||||
startLine = sourceFile.getLineAndCharacterFromPosition(tokenInfo.token.pos).line;
|
||||
var indentation =
|
||||
computeIndentation(tokenInfo.token, startLine, Constants.Unknown, parent, parentDynamicIndentation, startLine);
|
||||
|
||||
listDynamicIndentation = getDynamicIndentation(parent, parentStartLine, indentation.indentation, indentation.delta);
|
||||
consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation);
|
||||
}
|
||||
else {
|
||||
// consume any tokens that precede the list as child elements of 'node' using its indentation scope
|
||||
consumeTokenAndAdvanceScanner(tokenInfo, parent, parentDynamicIndentation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var inheritedIndentation = Constants.Unknown;
|
||||
for (var i = 0, len = nodes.length; i < len; ++i) {
|
||||
inheritedIndentation = processChildNode(nodes[i], inheritedIndentation, node, listDynamicIndentation, startLine, /*isListElement*/ true)
|
||||
}
|
||||
|
||||
if (listEndToken !== SyntaxKind.Unknown) {
|
||||
if (formattingScanner.isOnToken()) {
|
||||
var tokenInfo = formattingScanner.readTokenInfo(parent);
|
||||
if (tokenInfo.token.kind === listEndToken) {
|
||||
// consume list end token
|
||||
consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function consumeTokenAndAdvanceScanner(currentTokenInfo: TokenInfo, parent: Node, dynamicIndentation: DynamicIndentation): void {
|
||||
Debug.assert(rangeContainsRange(parent, currentTokenInfo.token));
|
||||
|
||||
var lastTriviaWasNewLine = formattingScanner.lastTrailingTriviaWasNewLine();
|
||||
var indentToken = false;
|
||||
|
||||
if (currentTokenInfo.leadingTrivia) {
|
||||
processTrivia(currentTokenInfo.leadingTrivia, parent, childContextNode, dynamicIndentation);
|
||||
}
|
||||
|
||||
var lineAdded: boolean;
|
||||
var isTokenInRange = rangeContainsRange(originalRange, currentTokenInfo.token);
|
||||
|
||||
var tokenStart = sourceFile.getLineAndCharacterFromPosition(currentTokenInfo.token.pos);
|
||||
if (isTokenInRange) {
|
||||
// save prevStartLine since processRange will overwrite this value with current ones
|
||||
var prevStartLine = previousRangeStartLine;
|
||||
lineAdded = processRange(currentTokenInfo.token, tokenStart, parent, childContextNode, dynamicIndentation);
|
||||
if (lineAdded !== undefined) {
|
||||
indentToken = lineAdded;
|
||||
}
|
||||
else {
|
||||
indentToken = lastTriviaWasNewLine && tokenStart.line !== prevStartLine;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentTokenInfo.trailingTrivia) {
|
||||
processTrivia(currentTokenInfo.trailingTrivia, parent, childContextNode, dynamicIndentation);
|
||||
}
|
||||
|
||||
if (indentToken) {
|
||||
var indentNextTokenOrTrivia = true;
|
||||
if (currentTokenInfo.leadingTrivia) {
|
||||
for (var i = 0, len = currentTokenInfo.leadingTrivia.length; i < len; ++i) {
|
||||
var triviaItem = currentTokenInfo.leadingTrivia[i];
|
||||
if (!rangeContainsRange(originalRange, triviaItem)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var triviaStartLine = sourceFile.getLineAndCharacterFromPosition(triviaItem.pos).line;
|
||||
switch (triviaItem.kind) {
|
||||
case SyntaxKind.MultiLineCommentTrivia:
|
||||
var commentIndentation = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind);
|
||||
indentMultilineComment(triviaItem, commentIndentation, /*firstLineIsIndented*/ !indentNextTokenOrTrivia);
|
||||
indentNextTokenOrTrivia = false;
|
||||
break;
|
||||
case SyntaxKind.SingleLineCommentTrivia:
|
||||
if (indentNextTokenOrTrivia) {
|
||||
var commentIndentation = dynamicIndentation.getIndentationForComment(currentTokenInfo.token.kind);
|
||||
insertIndentation(triviaItem.pos, commentIndentation, /*lineAdded*/ false);
|
||||
indentNextTokenOrTrivia = false;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.NewLineTrivia:
|
||||
indentNextTokenOrTrivia = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// indent token only if is it is in target range and does not overlap with any error ranges
|
||||
if (isTokenInRange && !rangeContainsError(currentTokenInfo.token)) {
|
||||
var tokenIndentation = dynamicIndentation.getIndentationForToken(tokenStart.line, currentTokenInfo.token.kind);
|
||||
insertIndentation(currentTokenInfo.token.pos, tokenIndentation, lineAdded);
|
||||
}
|
||||
}
|
||||
|
||||
formattingScanner.advance();
|
||||
|
||||
childContextNode = parent;
|
||||
}
|
||||
}
|
||||
|
||||
function processTrivia(trivia: TextRangeWithKind[], parent: Node, contextNode: Node, dynamicIndentation: DynamicIndentation): void {
|
||||
for (var i = 0, len = trivia.length; i < len; ++i) {
|
||||
var triviaItem = trivia[i];
|
||||
if (isComment(triviaItem.kind) && rangeContainsRange(originalRange, triviaItem)) {
|
||||
var triviaItemStart = sourceFile.getLineAndCharacterFromPosition(triviaItem.pos);
|
||||
processRange(triviaItem, triviaItemStart, parent, contextNode, dynamicIndentation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function processRange(range: TextRangeWithKind,
|
||||
rangeStart: LineAndCharacter,
|
||||
parent: Node,
|
||||
contextNode: Node,
|
||||
dynamicIndentation: DynamicIndentation): boolean {
|
||||
|
||||
var rangeHasError = rangeContainsError(range);
|
||||
var lineAdded: boolean;
|
||||
if (!rangeHasError && !previousRangeHasError) {
|
||||
if (!previousRange) {
|
||||
// trim whitespaces starting from the beginning of the span up to the current line
|
||||
var originalStart = sourceFile.getLineAndCharacterFromPosition(originalRange.pos);
|
||||
trimTrailingWhitespacesForLines(originalStart.line, rangeStart.line);
|
||||
}
|
||||
else {
|
||||
lineAdded =
|
||||
processPair(range, rangeStart.line, parent, previousRange, previousRangeStartLine, previousParent, contextNode, dynamicIndentation)
|
||||
}
|
||||
}
|
||||
|
||||
previousRange = range;
|
||||
previousParent = parent;
|
||||
previousRangeStartLine = rangeStart.line;
|
||||
previousRangeHasError = rangeHasError;
|
||||
|
||||
return lineAdded;
|
||||
}
|
||||
|
||||
function processPair(currentItem: TextRangeWithKind,
|
||||
currentStartLine: number,
|
||||
currentParent: Node,
|
||||
previousItem: TextRangeWithKind,
|
||||
previousStartLine: number,
|
||||
previousParent: Node,
|
||||
contextNode: Node,
|
||||
dynamicIndentation: DynamicIndentation): boolean {
|
||||
|
||||
formattingContext.updateContext(previousItem, previousParent, currentItem, currentParent, contextNode);
|
||||
|
||||
var rule = rulesProvider.getRulesMap().GetRule(formattingContext);
|
||||
|
||||
var trimTrailingWhitespaces: boolean;
|
||||
var lineAdded: boolean;
|
||||
if (rule) {
|
||||
applyRuleEdits(rule, previousItem, previousStartLine, currentItem, currentStartLine);
|
||||
|
||||
if (rule.Operation.Action & (RuleAction.Space | RuleAction.Delete) && currentStartLine !== previousStartLine) {
|
||||
// Handle the case where the next line is moved to be the end of this line.
|
||||
// In this case we don't indent the next line in the next pass.
|
||||
if (currentParent.getStart(sourceFile) === currentItem.pos) {
|
||||
lineAdded = false;
|
||||
}
|
||||
}
|
||||
else if (rule.Operation.Action & RuleAction.NewLine && currentStartLine === previousStartLine) {
|
||||
// Handle the case where token2 is moved to the new line.
|
||||
// In this case we indent token2 in the next pass but we set
|
||||
// sameLineIndent flag to notify the indenter that the indentation is within the line.
|
||||
if (currentParent.getStart(sourceFile) === currentItem.pos) {
|
||||
lineAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (lineAdded !== undefined) {
|
||||
dynamicIndentation.recomputeIndentation(lineAdded);
|
||||
}
|
||||
|
||||
// We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line
|
||||
trimTrailingWhitespaces =
|
||||
(rule.Operation.Action & (RuleAction.NewLine | RuleAction.Space)) &&
|
||||
rule.Flag !== RuleFlags.CanDeleteNewLines;
|
||||
}
|
||||
else {
|
||||
trimTrailingWhitespaces = true;
|
||||
}
|
||||
|
||||
if (currentStartLine !== previousStartLine && trimTrailingWhitespaces) {
|
||||
// We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line
|
||||
trimTrailingWhitespacesForLines(previousStartLine, currentStartLine, previousItem);
|
||||
}
|
||||
|
||||
return lineAdded;
|
||||
}
|
||||
|
||||
function insertIndentation(pos: number, indentation: number, lineAdded: boolean): void {
|
||||
var indentationString = getIndentationString(indentation, options);
|
||||
if (lineAdded) {
|
||||
// new line is added before the token by the formatting rules
|
||||
// insert indentation string at the very beginning of the token
|
||||
recordReplace(pos, 0, indentationString);
|
||||
}
|
||||
else {
|
||||
var tokenStart = sourceFile.getLineAndCharacterFromPosition(pos);
|
||||
if (indentation !== tokenStart.character - 1) {
|
||||
var startLinePosition = getStartPositionOfLine(tokenStart.line, sourceFile);
|
||||
recordReplace(startLinePosition, tokenStart.character - 1, indentationString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function indentMultilineComment(commentRange: TextRange, indentation: number, firstLineIsIndented: boolean) {
|
||||
// split comment in lines
|
||||
var startLine = sourceFile.getLineAndCharacterFromPosition(commentRange.pos).line;
|
||||
var endLine = sourceFile.getLineAndCharacterFromPosition(commentRange.end).line;
|
||||
|
||||
if (startLine === endLine) {
|
||||
if (!firstLineIsIndented) {
|
||||
// treat as single line comment
|
||||
insertIndentation(commentRange.pos, indentation, /*lineAdded*/ false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
var parts: TextRange[] = [];
|
||||
var startPos = commentRange.pos;
|
||||
for (var line = startLine; line < endLine; ++line) {
|
||||
var endOfLine = getEndLinePosition(line, sourceFile);
|
||||
parts.push({ pos: startPos, end: endOfLine });
|
||||
startPos = getStartPositionOfLine(line + 1, sourceFile);
|
||||
}
|
||||
|
||||
parts.push({ pos: startPos, end: commentRange.end });
|
||||
}
|
||||
|
||||
var startLinePos = getStartPositionOfLine(startLine, sourceFile);
|
||||
|
||||
var nonWhitespaceColumnInFirstPart =
|
||||
SmartIndenter.findFirstNonWhitespaceColumn(startLinePos, parts[0].pos, sourceFile, options);
|
||||
|
||||
if (indentation === nonWhitespaceColumnInFirstPart) {
|
||||
return;
|
||||
}
|
||||
|
||||
var startIndex = 0;
|
||||
if (firstLineIsIndented) {
|
||||
startIndex = 1;
|
||||
startLine++;
|
||||
}
|
||||
|
||||
// shift all parts on the delta size
|
||||
var delta = indentation - nonWhitespaceColumnInFirstPart;
|
||||
for (var i = startIndex, len = parts.length; i < len; ++i, ++startLine) {
|
||||
var startLinePos = getStartPositionOfLine(startLine, sourceFile);
|
||||
var nonWhitespaceColumn =
|
||||
i === 0
|
||||
? nonWhitespaceColumnInFirstPart
|
||||
: SmartIndenter.findFirstNonWhitespaceColumn(parts[i].pos, parts[i].end, sourceFile, options);
|
||||
|
||||
var newIndentation = nonWhitespaceColumn + delta;
|
||||
if (newIndentation > 0) {
|
||||
var indentationString = getIndentationString(newIndentation, options);
|
||||
recordReplace(startLinePos, nonWhitespaceColumn, indentationString);
|
||||
}
|
||||
else {
|
||||
recordDelete(startLinePos, nonWhitespaceColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function trimTrailingWhitespacesForLines(line1: number, line2: number, range?: TextRangeWithKind) {
|
||||
for (var line = line1; line < line2; ++line) {
|
||||
var lineStartPosition = getStartPositionOfLine(line, sourceFile);
|
||||
var lineEndPosition = getEndLinePosition(line, sourceFile);
|
||||
|
||||
// do not trim whitespaces in comments
|
||||
if (range && isComment(range.kind) && range.pos <= lineEndPosition && range.end > lineEndPosition) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var pos = lineEndPosition;
|
||||
while (pos >= lineStartPosition && isWhiteSpace(sourceFile.text.charCodeAt(pos))) {
|
||||
pos--;
|
||||
}
|
||||
if (pos !== lineEndPosition) {
|
||||
Debug.assert(pos === lineStartPosition || !isWhiteSpace(sourceFile.text.charCodeAt(pos)));
|
||||
recordDelete(pos + 1, lineEndPosition - pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function newTextChange(start: number, len: number, newText: string): TextChange {
|
||||
return { span: new TextSpan(start, len), newText }
|
||||
}
|
||||
|
||||
function recordDelete(start: number, len: number) {
|
||||
if (len) {
|
||||
edits.push(newTextChange(start, len, ""));
|
||||
}
|
||||
}
|
||||
|
||||
function recordReplace(start: number, len: number, newText: string) {
|
||||
if (len || newText) {
|
||||
edits.push(newTextChange(start, len, newText));
|
||||
}
|
||||
}
|
||||
|
||||
function applyRuleEdits(rule: Rule,
|
||||
previousRange: TextRangeWithKind,
|
||||
previousStartLine: number,
|
||||
currentRange: TextRangeWithKind,
|
||||
currentStartLine: number): void {
|
||||
|
||||
var between: TextRange;
|
||||
switch (rule.Operation.Action) {
|
||||
case RuleAction.Ignore:
|
||||
// no action required
|
||||
return;
|
||||
case RuleAction.Delete:
|
||||
if (previousRange.end !== currentRange.pos) {
|
||||
// delete characters starting from t1.end up to t2.pos exclusive
|
||||
recordDelete(previousRange.end, currentRange.pos - previousRange.end);
|
||||
}
|
||||
break;
|
||||
case RuleAction.NewLine:
|
||||
// exit early if we on different lines and rule cannot change number of newlines
|
||||
// if line1 and line2 are on subsequent lines then no edits are required - ok to exit
|
||||
// if line1 and line2 are separated with more than one newline - ok to exit since we cannot delete extra new lines
|
||||
if (rule.Flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) {
|
||||
return;
|
||||
}
|
||||
|
||||
// edit should not be applied only if we have one line feed between elements
|
||||
var lineDelta = currentStartLine - previousStartLine;
|
||||
if (lineDelta !== 1) {
|
||||
recordReplace(previousRange.end, currentRange.pos - previousRange.end, options.NewLineCharacter);
|
||||
}
|
||||
break;
|
||||
case RuleAction.Space:
|
||||
// exit early if we on different lines and rule cannot change number of newlines
|
||||
if (rule.Flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) {
|
||||
return;
|
||||
}
|
||||
|
||||
var posDelta = currentRange.pos - previousRange.end;
|
||||
if (posDelta !== 1 || sourceFile.text.charCodeAt(previousRange.end) !== CharacterCodes.space) {
|
||||
recordReplace(previousRange.end, currentRange.pos - previousRange.end, " ");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isSomeBlock(kind: SyntaxKind): boolean {
|
||||
switch (kind) {
|
||||
case SyntaxKind.Block:
|
||||
case SyntaxKind.FunctionBlock:
|
||||
case SyntaxKind.TryBlock:
|
||||
case SyntaxKind.CatchBlock:
|
||||
case SyntaxKind.FinallyBlock:
|
||||
case SyntaxKind.ModuleBlock:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getOpenTokenForList(node: Node, list: Node[]) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
if ((<FunctionDeclaration>node).typeParameters === list) {
|
||||
return SyntaxKind.LessThanToken;
|
||||
}
|
||||
else if ((<FunctionDeclaration>node).parameters === list) {
|
||||
return SyntaxKind.OpenParenToken;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
if ((<CallExpression>node).typeArguments === list) {
|
||||
return SyntaxKind.LessThanToken;
|
||||
}
|
||||
else if ((<CallExpression>node).arguments === list) {
|
||||
return SyntaxKind.OpenParenToken;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.TypeReference:
|
||||
if ((<TypeReferenceNode>node).typeArguments === list) {
|
||||
return SyntaxKind.LessThanToken;
|
||||
}
|
||||
}
|
||||
|
||||
return SyntaxKind.Unknown;
|
||||
}
|
||||
|
||||
function getCloseTokenForOpenToken(kind: SyntaxKind) {
|
||||
switch (kind) {
|
||||
case SyntaxKind.OpenParenToken:
|
||||
return SyntaxKind.CloseParenToken;
|
||||
case SyntaxKind.LessThanToken:
|
||||
return SyntaxKind.GreaterThanToken;
|
||||
}
|
||||
|
||||
return SyntaxKind.Unknown;
|
||||
}
|
||||
}
|
||||
@@ -1,315 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export class Formatter extends MultipleTokenIndenter {
|
||||
private previousTokenSpan: TokenSpan = null;
|
||||
private previousTokenParent: IndentationNodeContext = null;
|
||||
|
||||
// TODO: implement it with skipped tokens in Fidelity
|
||||
private scriptHasErrors: boolean = false;
|
||||
|
||||
private rulesProvider: RulesProvider;
|
||||
private formattingRequestKind: FormattingRequestKind;
|
||||
private formattingContext: FormattingContext;
|
||||
|
||||
constructor(textSpan: TextSpan,
|
||||
sourceUnit: SourceUnitSyntax,
|
||||
indentFirstToken: boolean,
|
||||
options: FormattingOptions,
|
||||
snapshot: ITextSnapshot,
|
||||
rulesProvider: RulesProvider,
|
||||
formattingRequestKind: FormattingRequestKind) {
|
||||
|
||||
super(textSpan, sourceUnit, snapshot, indentFirstToken, options);
|
||||
|
||||
this.previousTokenParent = this.parent().clone(this.indentationNodeContextPool());
|
||||
|
||||
this.rulesProvider = rulesProvider;
|
||||
this.formattingRequestKind = formattingRequestKind;
|
||||
this.formattingContext = new FormattingContext(this.snapshot(), this.formattingRequestKind);
|
||||
}
|
||||
|
||||
public static getEdits(textSpan: TextSpan,
|
||||
sourceUnit: SourceUnitSyntax,
|
||||
options: FormattingOptions,
|
||||
indentFirstToken: boolean,
|
||||
snapshot: ITextSnapshot,
|
||||
rulesProvider: RulesProvider,
|
||||
formattingRequestKind: FormattingRequestKind): TextEditInfo[] {
|
||||
var walker = new Formatter(textSpan, sourceUnit, indentFirstToken, options, snapshot, rulesProvider, formattingRequestKind);
|
||||
walker.walk(sourceUnit);
|
||||
return walker.edits();
|
||||
}
|
||||
|
||||
public visitTokenInSpan(token: ISyntaxToken): void {
|
||||
if (token.fullWidth() !== 0) {
|
||||
var tokenSpan = new TextSpan(this.position() + token.leadingTriviaWidth(), width(token));
|
||||
if (this.textSpan().containsTextSpan(tokenSpan)) {
|
||||
this.processToken(token);
|
||||
}
|
||||
}
|
||||
|
||||
// Call the base class to process the token and indent it if needed
|
||||
super.visitTokenInSpan(token);
|
||||
}
|
||||
|
||||
private processToken(token: ISyntaxToken): void {
|
||||
var position = this.position();
|
||||
|
||||
// Extract any leading comments
|
||||
if (token.leadingTriviaWidth() !== 0) {
|
||||
this.processTrivia(token.leadingTrivia(), position);
|
||||
position += token.leadingTriviaWidth();
|
||||
}
|
||||
|
||||
// Push the token
|
||||
var currentTokenSpan = new TokenSpan(token.kind, position, width(token));
|
||||
if (!this.parent().hasSkippedOrMissingTokenChild()) {
|
||||
if (this.previousTokenSpan) {
|
||||
// Note that formatPair calls TrimWhitespaceInLineRange in between the 2 tokens
|
||||
this.formatPair(this.previousTokenSpan, this.previousTokenParent, currentTokenSpan, this.parent());
|
||||
}
|
||||
else {
|
||||
// We still want to trim whitespace even if it is the first trivia of the first token. Trim from the beginning of the span to the trivia
|
||||
this.trimWhitespaceInLineRange(this.getLineNumber(this.textSpan()), this.getLineNumber(currentTokenSpan));
|
||||
}
|
||||
}
|
||||
this.previousTokenSpan = currentTokenSpan;
|
||||
if (this.previousTokenParent) {
|
||||
// Make sure to clear the previous parent before assigning a new value to it
|
||||
this.indentationNodeContextPool().releaseNode(this.previousTokenParent, /* recursive */true);
|
||||
}
|
||||
this.previousTokenParent = this.parent().clone(this.indentationNodeContextPool());
|
||||
position += width(token);
|
||||
}
|
||||
|
||||
private processTrivia(triviaList: ISyntaxTriviaList, fullStart: number) {
|
||||
var position = fullStart;
|
||||
|
||||
for (var i = 0, n = triviaList.count(); i < n ; i++) {
|
||||
var trivia = triviaList.syntaxTriviaAt(i);
|
||||
// For a comment, format it like it is a token. For skipped text, eat it up as a token, but skip the formatting
|
||||
if (trivia.isComment() || trivia.isSkippedToken()) {
|
||||
var currentTokenSpan = new TokenSpan(trivia.kind, position, trivia.fullWidth());
|
||||
if (this.textSpan().containsTextSpan(currentTokenSpan)) {
|
||||
if (trivia.isComment() && this.previousTokenSpan) {
|
||||
// Note that formatPair calls TrimWhitespaceInLineRange in between the 2 tokens
|
||||
this.formatPair(this.previousTokenSpan, this.previousTokenParent, currentTokenSpan, this.parent());
|
||||
}
|
||||
else {
|
||||
// We still want to trim whitespace even if it is the first trivia of the first token. Trim from the beginning of the span to the trivia
|
||||
var startLine = this.getLineNumber(this.previousTokenSpan || this.textSpan());
|
||||
this.trimWhitespaceInLineRange(startLine, this.getLineNumber(currentTokenSpan));
|
||||
}
|
||||
this.previousTokenSpan = currentTokenSpan;
|
||||
if (this.previousTokenParent) {
|
||||
// Make sure to clear the previous parent before assigning a new value to it
|
||||
this.indentationNodeContextPool().releaseNode(this.previousTokenParent, /* recursive */true);
|
||||
}
|
||||
this.previousTokenParent = this.parent().clone(this.indentationNodeContextPool());
|
||||
}
|
||||
}
|
||||
|
||||
position += trivia.fullWidth();
|
||||
}
|
||||
}
|
||||
|
||||
private findCommonParents(parent1: IndentationNodeContext, parent2: IndentationNodeContext): IndentationNodeContext {
|
||||
// TODO: disable debug assert message
|
||||
|
||||
var shallowParent: IndentationNodeContext;
|
||||
var shallowParentDepth: number;
|
||||
var deepParent: IndentationNodeContext;
|
||||
var deepParentDepth: number;
|
||||
|
||||
if (parent1.depth() < parent2.depth()) {
|
||||
shallowParent = parent1;
|
||||
shallowParentDepth = parent1.depth();
|
||||
deepParent = parent2;
|
||||
deepParentDepth = parent2.depth();
|
||||
}
|
||||
else {
|
||||
shallowParent = parent2;
|
||||
shallowParentDepth = parent2.depth();
|
||||
deepParent = parent1;
|
||||
deepParentDepth = parent1.depth();
|
||||
}
|
||||
|
||||
Debug.assert(shallowParentDepth >= 0, "Expected shallowParentDepth >= 0");
|
||||
Debug.assert(deepParentDepth >= 0, "Expected deepParentDepth >= 0");
|
||||
Debug.assert(deepParentDepth >= shallowParentDepth, "Expected deepParentDepth >= shallowParentDepth");
|
||||
|
||||
while (deepParentDepth > shallowParentDepth) {
|
||||
deepParent = <IndentationNodeContext>deepParent.parent();
|
||||
deepParentDepth--;
|
||||
}
|
||||
|
||||
Debug.assert(deepParentDepth === shallowParentDepth, "Expected deepParentDepth === shallowParentDepth");
|
||||
|
||||
while (deepParent.node() && shallowParent.node()) {
|
||||
if (deepParent.node() === shallowParent.node()) {
|
||||
return deepParent;
|
||||
}
|
||||
deepParent = <IndentationNodeContext>deepParent.parent();
|
||||
shallowParent = <IndentationNodeContext>shallowParent.parent();
|
||||
}
|
||||
|
||||
// The root should be the first element in the parent chain, we can not be here unless something wrong
|
||||
// happened along the way
|
||||
throw Errors.invalidOperation();
|
||||
}
|
||||
|
||||
private formatPair(t1: TokenSpan, t1Parent: IndentationNodeContext, t2: TokenSpan, t2Parent: IndentationNodeContext): void {
|
||||
var token1Line = this.getLineNumber(t1);
|
||||
var token2Line = this.getLineNumber(t2);
|
||||
|
||||
// Find common parent
|
||||
var commonParent= this.findCommonParents(t1Parent, t2Parent);
|
||||
|
||||
// Update the context
|
||||
this.formattingContext.updateContext(t1, t1Parent, t2, t2Parent, commonParent);
|
||||
|
||||
// Find rules matching the current context
|
||||
var rule = this.rulesProvider.getRulesMap().GetRule(this.formattingContext);
|
||||
|
||||
if (rule != null) {
|
||||
// Record edits from the rule
|
||||
this.RecordRuleEdits(rule, t1, t2);
|
||||
|
||||
// Handle the case where the next line is moved to be the end of this line.
|
||||
// In this case we don't indent the next line in the next pass.
|
||||
if ((rule.Operation.Action == RuleAction.Space || rule.Operation.Action == RuleAction.Delete) &&
|
||||
token1Line != token2Line) {
|
||||
this.forceSkipIndentingNextToken(t2.start());
|
||||
}
|
||||
|
||||
// Handle the case where token2 is moved to the new line.
|
||||
// In this case we indent token2 in the next pass but we set
|
||||
// sameLineIndent flag to notify the indenter that the indentation is within the line.
|
||||
if (rule.Operation.Action == RuleAction.NewLine && token1Line == token2Line) {
|
||||
this.forceIndentNextToken(t2.start());
|
||||
}
|
||||
}
|
||||
|
||||
// We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line
|
||||
if (token1Line != token2Line && (!rule || (rule.Operation.Action != RuleAction.Delete && rule.Flag != RuleFlags.CanDeleteNewLines))) {
|
||||
this.trimWhitespaceInLineRange(token1Line, token2Line, t1);
|
||||
}
|
||||
}
|
||||
|
||||
private getLineNumber(span: TextSpan): number {
|
||||
return this.snapshot().getLineNumberFromPosition(span.start());
|
||||
}
|
||||
|
||||
private trimWhitespaceInLineRange(startLine: number, endLine: number, token?: TokenSpan): void {
|
||||
for (var lineNumber = startLine; lineNumber < endLine; ++lineNumber) {
|
||||
var line = this.snapshot().getLineFromLineNumber(lineNumber);
|
||||
|
||||
this.trimWhitespace(line, token);
|
||||
}
|
||||
}
|
||||
|
||||
private trimWhitespace(line: ITextSnapshotLine, token?: TokenSpan): void {
|
||||
// Don't remove the trailing spaces inside comments (this includes line comments and block comments)
|
||||
if (token && (token.kind == SyntaxKind.MultiLineCommentTrivia || token.kind == SyntaxKind.SingleLineCommentTrivia) && token.start() <= line.endPosition() && token.end() >= line.endPosition())
|
||||
return;
|
||||
|
||||
var text = line.getText();
|
||||
var index = 0;
|
||||
|
||||
for (index = text.length - 1; index >= 0; --index) {
|
||||
if (!CharacterInfo.isWhitespace(text.charCodeAt(index))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
++index;
|
||||
|
||||
if (index < text.length) {
|
||||
this.recordEdit(line.startPosition() + index, line.length() - index, "");
|
||||
}
|
||||
}
|
||||
|
||||
private RecordRuleEdits(rule: Rule, t1: TokenSpan, t2: TokenSpan): void {
|
||||
if (rule.Operation.Action == RuleAction.Ignore) {
|
||||
return;
|
||||
}
|
||||
|
||||
var betweenSpan: TextSpan;
|
||||
|
||||
switch (rule.Operation.Action) {
|
||||
case RuleAction.Delete:
|
||||
{
|
||||
betweenSpan = new TextSpan(t1.end(), t2.start() - t1.end());
|
||||
|
||||
if (betweenSpan.length() > 0) {
|
||||
this.recordEdit(betweenSpan.start(), betweenSpan.length(), "");
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RuleAction.NewLine:
|
||||
{
|
||||
if (!(rule.Flag == RuleFlags.CanDeleteNewLines || this.getLineNumber(t1) == this.getLineNumber(t2))) {
|
||||
return;
|
||||
}
|
||||
|
||||
betweenSpan = new TextSpan(t1.end(), t2.start() - t1.end());
|
||||
|
||||
var doEdit = false;
|
||||
var betweenText = this.snapshot().getText(betweenSpan);
|
||||
|
||||
var lineFeedLoc = betweenText.indexOf(this.options.newLineCharacter);
|
||||
if (lineFeedLoc < 0) {
|
||||
// no linefeeds, do the edit
|
||||
doEdit = true;
|
||||
}
|
||||
else {
|
||||
// We only require one line feed. If there is another one, do the edit
|
||||
lineFeedLoc = betweenText.indexOf(this.options.newLineCharacter, lineFeedLoc + 1);
|
||||
if (lineFeedLoc >= 0) {
|
||||
doEdit = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (doEdit) {
|
||||
this.recordEdit(betweenSpan.start(), betweenSpan.length(), this.options.newLineCharacter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RuleAction.Space:
|
||||
{
|
||||
if (!(rule.Flag == RuleFlags.CanDeleteNewLines || this.getLineNumber(t1) == this.getLineNumber(t2))) {
|
||||
return;
|
||||
}
|
||||
|
||||
betweenSpan = new TextSpan(t1.end(), t2.start() - t1.end());
|
||||
|
||||
if (betweenSpan.length() > 1 || this.snapshot().getText(betweenSpan) != " ") {
|
||||
this.recordEdit(betweenSpan.start(), betweenSpan.length(), " ");
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,48 +13,48 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
/// <reference path="formatting.ts"/>
|
||||
/// <reference path="references.ts"/>
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
module ts.formatting {
|
||||
export class FormattingContext {
|
||||
public currentTokenSpan: TokenSpan = null;
|
||||
public nextTokenSpan: TokenSpan = null;
|
||||
public contextNode: IndentationNodeContext = null;
|
||||
public currentTokenParent: IndentationNodeContext = null;
|
||||
public nextTokenParent: IndentationNodeContext = null;
|
||||
public currentTokenSpan: TextRangeWithKind;
|
||||
public nextTokenSpan: TextRangeWithKind;
|
||||
public contextNode: Node;
|
||||
public currentTokenParent: Node;
|
||||
public nextTokenParent: Node;
|
||||
|
||||
private contextNodeAllOnSameLine: boolean = null;
|
||||
private nextNodeAllOnSameLine: boolean = null;
|
||||
private tokensAreOnSameLine: boolean = null;
|
||||
private contextNodeBlockIsOnOneLine: boolean = null;
|
||||
private nextNodeBlockIsOnOneLine: boolean = null;
|
||||
private contextNodeAllOnSameLine: boolean;
|
||||
private nextNodeAllOnSameLine: boolean;
|
||||
private tokensAreOnSameLine: boolean;
|
||||
private contextNodeBlockIsOnOneLine: boolean;
|
||||
private nextNodeBlockIsOnOneLine: boolean;
|
||||
|
||||
constructor(private snapshot: ITextSnapshot, public formattingRequestKind: FormattingRequestKind) {
|
||||
Debug.assert(this.snapshot != null, "snapshot is null");
|
||||
constructor(private sourceFile: SourceFile, public formattingRequestKind: FormattingRequestKind) {
|
||||
}
|
||||
|
||||
public updateContext(currentTokenSpan: TokenSpan, currentTokenParent: IndentationNodeContext, nextTokenSpan: TokenSpan, nextTokenParent: IndentationNodeContext, commonParent: IndentationNodeContext) {
|
||||
Debug.assert(currentTokenSpan != null, "currentTokenSpan is null");
|
||||
Debug.assert(currentTokenParent != null, "currentTokenParent is null");
|
||||
Debug.assert(nextTokenSpan != null, "nextTokenSpan is null");
|
||||
Debug.assert(nextTokenParent != null, "nextTokenParent is null");
|
||||
Debug.assert(commonParent != null, "commonParent is null");
|
||||
public updateContext(currentRange: TextRangeWithKind, currentTokenParent: Node, nextRange: TextRangeWithKind, nextTokenParent: Node, commonParent: Node) {
|
||||
Debug.assert(currentRange !== undefined, "currentTokenSpan is null");
|
||||
Debug.assert(currentTokenParent !== undefined, "currentTokenParent is null");
|
||||
Debug.assert(nextRange !== undefined, "nextTokenSpan is null");
|
||||
Debug.assert(nextTokenParent !== undefined, "nextTokenParent is null");
|
||||
Debug.assert(commonParent !== undefined, "commonParent is null");
|
||||
|
||||
this.currentTokenSpan = currentTokenSpan;
|
||||
this.currentTokenSpan = currentRange;
|
||||
this.currentTokenParent = currentTokenParent;
|
||||
this.nextTokenSpan = nextTokenSpan;
|
||||
this.nextTokenSpan = nextRange;
|
||||
this.nextTokenParent = nextTokenParent;
|
||||
this.contextNode = commonParent;
|
||||
|
||||
this.contextNodeAllOnSameLine = null;
|
||||
this.nextNodeAllOnSameLine = null;
|
||||
this.tokensAreOnSameLine = null;
|
||||
this.contextNodeBlockIsOnOneLine = null;
|
||||
this.nextNodeBlockIsOnOneLine = null;
|
||||
// drop cached results
|
||||
this.contextNodeAllOnSameLine = undefined;
|
||||
this.nextNodeAllOnSameLine = undefined;
|
||||
this.tokensAreOnSameLine = undefined;
|
||||
this.contextNodeBlockIsOnOneLine = undefined;
|
||||
this.nextNodeBlockIsOnOneLine = undefined;
|
||||
}
|
||||
|
||||
public ContextNodeAllOnSameLine(): boolean {
|
||||
if (this.contextNodeAllOnSameLine === null) {
|
||||
if (this.contextNodeAllOnSameLine === undefined) {
|
||||
this.contextNodeAllOnSameLine = this.NodeIsOnOneLine(this.contextNode);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
public NextNodeAllOnSameLine(): boolean {
|
||||
if (this.nextNodeAllOnSameLine === null) {
|
||||
if (this.nextNodeAllOnSameLine === undefined) {
|
||||
this.nextNodeAllOnSameLine = this.NodeIsOnOneLine(this.nextTokenParent);
|
||||
}
|
||||
|
||||
@@ -70,10 +70,9 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
public TokensAreOnSameLine(): boolean {
|
||||
if (this.tokensAreOnSameLine === null) {
|
||||
var startLine = this.snapshot.getLineNumberFromPosition(this.currentTokenSpan.start());
|
||||
var endLine = this.snapshot.getLineNumberFromPosition(this.nextTokenSpan.start());
|
||||
|
||||
if (this.tokensAreOnSameLine === undefined) {
|
||||
var startLine = this.sourceFile.getLineAndCharacterFromPosition(this.currentTokenSpan.pos).line;
|
||||
var endLine = this.sourceFile.getLineAndCharacterFromPosition(this.nextTokenSpan.pos).line;
|
||||
this.tokensAreOnSameLine = (startLine == endLine);
|
||||
}
|
||||
|
||||
@@ -81,7 +80,7 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
public ContextNodeBlockIsOnOneLine() {
|
||||
if (this.contextNodeBlockIsOnOneLine === null) {
|
||||
if (this.contextNodeBlockIsOnOneLine === undefined) {
|
||||
this.contextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.contextNode);
|
||||
}
|
||||
|
||||
@@ -89,28 +88,28 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
public NextNodeBlockIsOnOneLine() {
|
||||
if (this.nextNodeBlockIsOnOneLine === null) {
|
||||
if (this.nextNodeBlockIsOnOneLine === undefined) {
|
||||
this.nextNodeBlockIsOnOneLine = this.BlockIsOnOneLine(this.nextTokenParent);
|
||||
}
|
||||
|
||||
return this.nextNodeBlockIsOnOneLine;
|
||||
}
|
||||
|
||||
public NodeIsOnOneLine(node: IndentationNodeContext): boolean {
|
||||
var startLine = this.snapshot.getLineNumberFromPosition(node.start());
|
||||
var endLine = this.snapshot.getLineNumberFromPosition(node.end());
|
||||
|
||||
private NodeIsOnOneLine(node: Node): boolean {
|
||||
var startLine = this.sourceFile.getLineAndCharacterFromPosition(node.getStart(this.sourceFile)).line;
|
||||
var endLine = this.sourceFile.getLineAndCharacterFromPosition(node.getEnd()).line;
|
||||
return startLine == endLine;
|
||||
}
|
||||
|
||||
// Now we know we have a block (or a fake block represented by some other kind of node with an open and close brace as children).
|
||||
// IMPORTANT!!! This relies on the invariant that IsBlockContext must return true ONLY for nodes with open and close braces as immediate children
|
||||
public BlockIsOnOneLine(node: IndentationNodeContext): boolean {
|
||||
var block = <BlockSyntax>node.node();
|
||||
|
||||
// Now check if they are on the same line
|
||||
return this.snapshot.getLineNumberFromPosition(fullEnd(block.openBraceToken)) ===
|
||||
this.snapshot.getLineNumberFromPosition(start(block.closeBraceToken));
|
||||
private BlockIsOnOneLine(node: Node): boolean {
|
||||
var openBrace = findChildOfKind(node, SyntaxKind.OpenBraceToken, this.sourceFile);
|
||||
var closeBrace = findChildOfKind(node, SyntaxKind.CloseBraceToken, this.sourceFile);
|
||||
if (openBrace && closeBrace) {
|
||||
var startLine = this.sourceFile.getLineAndCharacterFromPosition(openBrace.getEnd()).line;
|
||||
var endLine = this.sourceFile.getLineAndCharacterFromPosition(closeBrace.getStart(this.sourceFile)).line;
|
||||
return startLine === endLine;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
/// <reference path="formatting.ts"/>
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export class FormattingManager {
|
||||
private options: FormattingOptions;
|
||||
|
||||
constructor(private syntaxTree: SyntaxTree,
|
||||
private snapshot: ITextSnapshot,
|
||||
private rulesProvider: RulesProvider,
|
||||
editorOptions: ts.EditorOptions) {
|
||||
//
|
||||
// TODO: convert to use FormattingOptions instead of EditorOptions
|
||||
this.options = new FormattingOptions(!editorOptions.ConvertTabsToSpaces, editorOptions.TabSize, editorOptions.IndentSize, editorOptions.NewLineCharacter)
|
||||
}
|
||||
|
||||
public formatSelection(minChar: number, limChar: number): ts.TextChange[] {
|
||||
var span = TextSpan.fromBounds(minChar, limChar);
|
||||
return this.formatSpan(span, FormattingRequestKind.FormatSelection);
|
||||
}
|
||||
|
||||
public formatDocument(): ts.TextChange[] {
|
||||
var span = TextSpan.fromBounds(0, this.snapshot.getLength());
|
||||
return this.formatSpan(span, FormattingRequestKind.FormatDocument);
|
||||
}
|
||||
|
||||
public formatOnSemicolon(caretPosition: number): ts.TextChange[] {
|
||||
var sourceUnit = this.syntaxTree.sourceUnit();
|
||||
var semicolonPositionedToken = findToken(sourceUnit, caretPosition - 1);
|
||||
|
||||
if (semicolonPositionedToken.kind === SyntaxKind.SemicolonToken) {
|
||||
// Find the outer most parent that this semicolon terminates
|
||||
var current: ISyntaxElement = semicolonPositionedToken;
|
||||
while (current.parent !== null &&
|
||||
fullEnd(current.parent) === fullEnd(semicolonPositionedToken) &&
|
||||
current.parent.kind !== SyntaxKind.List) {
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
// Compute the span
|
||||
var span = new TextSpan(fullStart(current), fullWidth(current));
|
||||
|
||||
// Format the span
|
||||
return this.formatSpan(span, FormattingRequestKind.FormatOnSemicolon);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public formatOnClosingCurlyBrace(caretPosition: number): ts.TextChange[] {
|
||||
var sourceUnit = this.syntaxTree.sourceUnit();
|
||||
var closeBracePositionedToken = findToken(sourceUnit, caretPosition - 1);
|
||||
|
||||
if (closeBracePositionedToken.kind === SyntaxKind.CloseBraceToken) {
|
||||
// Find the outer most parent that this closing brace terminates
|
||||
var current: ISyntaxElement = closeBracePositionedToken;
|
||||
while (current.parent !== null &&
|
||||
fullEnd(current.parent) === fullEnd(closeBracePositionedToken) &&
|
||||
current.parent.kind !== SyntaxKind.List) {
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
// Compute the span
|
||||
var span = new TextSpan(fullStart(current), fullWidth(current));
|
||||
|
||||
// Format the span
|
||||
return this.formatSpan(span, FormattingRequestKind.FormatOnClosingCurlyBrace);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public formatOnEnter(caretPosition: number): ts.TextChange[] {
|
||||
var lineNumber = this.snapshot.getLineNumberFromPosition(caretPosition);
|
||||
|
||||
if (lineNumber > 0) {
|
||||
// Format both lines
|
||||
var prevLine = this.snapshot.getLineFromLineNumber(lineNumber - 1);
|
||||
var currentLine = this.snapshot.getLineFromLineNumber(lineNumber);
|
||||
var span = TextSpan.fromBounds(prevLine.startPosition(), currentLine.endPosition());
|
||||
|
||||
// Format the span
|
||||
return this.formatSpan(span, FormattingRequestKind.FormatOnEnter);
|
||||
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
private formatSpan(span: TextSpan, formattingRequestKind: FormattingRequestKind): ts.TextChange[] {
|
||||
// Always format from the beginning of the line
|
||||
var startLine = this.snapshot.getLineFromPosition(span.start());
|
||||
span = TextSpan.fromBounds(startLine.startPosition(), span.end());
|
||||
|
||||
var result: ts.TextChange[] = [];
|
||||
|
||||
var formattingEdits = Formatter.getEdits(span, this.syntaxTree.sourceUnit(), this.options, true, this.snapshot, this.rulesProvider, formattingRequestKind);
|
||||
|
||||
//
|
||||
// TODO: Change the ILanguageService interface to return TextEditInfo (with start, and length) instead of TextEdit (with minChar and limChar)
|
||||
formattingEdits.forEach(item => {
|
||||
result.push({
|
||||
span: new TextSpan(item.position, item.length),
|
||||
newText: item.replaceWith
|
||||
});
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,15 +13,14 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
/// <reference path="formatting.ts"/>
|
||||
/// <reference path="references.ts"/>
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export enum FormattingRequestKind {
|
||||
module ts.formatting {
|
||||
export const enum FormattingRequestKind {
|
||||
FormatDocument,
|
||||
FormatSelection,
|
||||
FormatOnEnter,
|
||||
FormatOnSemicolon,
|
||||
FormatOnClosingCurlyBrace,
|
||||
FormatOnPaste
|
||||
FormatOnClosingCurlyBrace
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
/// <reference path="..\formatting.ts"/>
|
||||
/// <reference path="..\..\compiler\scanner.ts"/>
|
||||
|
||||
module ts.formatting {
|
||||
var scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ false);
|
||||
|
||||
export interface FormattingScanner {
|
||||
advance(): void;
|
||||
isOnToken(): boolean;
|
||||
readTokenInfo(n: Node): TokenInfo;
|
||||
lastTrailingTriviaWasNewLine(): boolean;
|
||||
close(): void;
|
||||
}
|
||||
|
||||
const enum ScanAction{
|
||||
Scan,
|
||||
RescanGreaterThanToken,
|
||||
RescanSlashToken,
|
||||
RescanTemplateToken
|
||||
}
|
||||
|
||||
export function getFormattingScanner(sourceFile: SourceFile, startPos: number, endPos: number): FormattingScanner {
|
||||
|
||||
scanner.setText(sourceFile.text);
|
||||
scanner.setTextPos(startPos);
|
||||
|
||||
var wasNewLine: boolean = true;
|
||||
var leadingTrivia: TextRangeWithKind[];
|
||||
var trailingTrivia: TextRangeWithKind[];
|
||||
|
||||
var savedPos: number;
|
||||
var lastScanAction: ScanAction;
|
||||
var lastTokenInfo: TokenInfo;
|
||||
|
||||
return {
|
||||
advance: advance,
|
||||
readTokenInfo: readTokenInfo,
|
||||
isOnToken: isOnToken,
|
||||
lastTrailingTriviaWasNewLine: () => wasNewLine,
|
||||
close: () => {
|
||||
lastTokenInfo = undefined;
|
||||
scanner.setText(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
function advance(): void {
|
||||
lastTokenInfo = undefined;
|
||||
var isStarted = scanner.getStartPos() !== startPos;
|
||||
|
||||
if (isStarted) {
|
||||
if (trailingTrivia) {
|
||||
Debug.assert(trailingTrivia.length !== 0);
|
||||
wasNewLine = trailingTrivia[trailingTrivia.length - 1].kind === SyntaxKind.NewLineTrivia;
|
||||
}
|
||||
else {
|
||||
wasNewLine = false;
|
||||
}
|
||||
}
|
||||
|
||||
leadingTrivia = undefined;
|
||||
trailingTrivia = undefined;
|
||||
|
||||
if (!isStarted) {
|
||||
scanner.scan();
|
||||
}
|
||||
|
||||
var t: SyntaxKind;
|
||||
var pos = scanner.getStartPos();
|
||||
|
||||
// Read leading trivia and token
|
||||
while (pos < endPos) {
|
||||
var t = scanner.getToken();
|
||||
if (!isTrivia(t)) {
|
||||
break;
|
||||
}
|
||||
|
||||
// consume leading trivia
|
||||
scanner.scan();
|
||||
var item = {
|
||||
pos: pos,
|
||||
end: scanner.getStartPos(),
|
||||
kind: t
|
||||
}
|
||||
|
||||
pos = scanner.getStartPos();
|
||||
|
||||
if (!leadingTrivia) {
|
||||
leadingTrivia = [];
|
||||
}
|
||||
leadingTrivia.push(item);
|
||||
}
|
||||
|
||||
savedPos = scanner.getStartPos();
|
||||
}
|
||||
|
||||
function shouldRescanGreaterThanToken(container: Node): boolean {
|
||||
if (container.kind !== SyntaxKind.BinaryExpression) {
|
||||
return false;
|
||||
}
|
||||
switch ((<BinaryExpression>container).operator) {
|
||||
case SyntaxKind.GreaterThanEqualsToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanEqualsToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
|
||||
case SyntaxKind.GreaterThanGreaterThanToken:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function shouldRescanSlashToken(container: Node): boolean {
|
||||
return container.kind === SyntaxKind.RegularExpressionLiteral;
|
||||
}
|
||||
|
||||
function shouldRescanTemplateToken(container: Node): boolean {
|
||||
return container.kind === SyntaxKind.TemplateSpan;
|
||||
}
|
||||
|
||||
function startsWithSlashToken(t: SyntaxKind): boolean {
|
||||
return t === SyntaxKind.SlashToken || t === SyntaxKind.SlashEqualsToken;
|
||||
}
|
||||
|
||||
function readTokenInfo(n: Node): TokenInfo {
|
||||
if (!isOnToken()) {
|
||||
// scanner is not on the token (either advance was not called yet or scanner is already past the end position)
|
||||
return {
|
||||
leadingTrivia: leadingTrivia,
|
||||
trailingTrivia: undefined,
|
||||
token: undefined
|
||||
};
|
||||
}
|
||||
|
||||
// normally scanner returns the smallest available token
|
||||
// check the kind of context node to determine if scanner should have more greedy behavior and consume more text.
|
||||
var expectedScanAction =
|
||||
shouldRescanGreaterThanToken(n)
|
||||
? ScanAction.RescanGreaterThanToken
|
||||
: shouldRescanSlashToken(n)
|
||||
? ScanAction.RescanSlashToken
|
||||
: shouldRescanTemplateToken(n)
|
||||
? ScanAction.RescanTemplateToken
|
||||
: ScanAction.Scan
|
||||
|
||||
if (lastTokenInfo && expectedScanAction === lastScanAction) {
|
||||
// readTokenInfo was called before with the same expected scan action.
|
||||
// No need to re-scan text, return existing 'lastTokenInfo'
|
||||
return lastTokenInfo;
|
||||
}
|
||||
|
||||
if (scanner.getStartPos() !== savedPos) {
|
||||
Debug.assert(lastTokenInfo !== undefined);
|
||||
// readTokenInfo was called before but scan action differs - rescan text
|
||||
scanner.setTextPos(savedPos);
|
||||
scanner.scan();
|
||||
}
|
||||
|
||||
var currentToken = scanner.getToken();
|
||||
|
||||
if (expectedScanAction === ScanAction.RescanGreaterThanToken && currentToken === SyntaxKind.GreaterThanToken) {
|
||||
currentToken = scanner.reScanGreaterToken();
|
||||
Debug.assert((<BinaryExpression>n).operator === currentToken);
|
||||
lastScanAction = ScanAction.RescanGreaterThanToken;
|
||||
}
|
||||
else if (expectedScanAction === ScanAction.RescanSlashToken && startsWithSlashToken(currentToken)) {
|
||||
currentToken = scanner.reScanSlashToken();
|
||||
Debug.assert(n.kind === currentToken);
|
||||
lastScanAction = ScanAction.RescanSlashToken;
|
||||
}
|
||||
else if (expectedScanAction === ScanAction.RescanTemplateToken && currentToken === SyntaxKind.CloseBraceToken) {
|
||||
currentToken = scanner.reScanTemplateToken();
|
||||
lastScanAction = ScanAction.RescanTemplateToken;
|
||||
}
|
||||
else {
|
||||
lastScanAction = ScanAction.Scan;
|
||||
}
|
||||
|
||||
var token: TextRangeWithKind = {
|
||||
pos: scanner.getStartPos(),
|
||||
end: scanner.getTextPos(),
|
||||
kind: currentToken
|
||||
}
|
||||
|
||||
// consume trailing trivia
|
||||
while(scanner.getStartPos() < endPos) {
|
||||
currentToken = scanner.scan();
|
||||
if (!isTrivia(currentToken)) {
|
||||
break;
|
||||
}
|
||||
var trivia = {
|
||||
pos: scanner.getStartPos(),
|
||||
end: scanner.getTextPos(),
|
||||
kind: currentToken
|
||||
};
|
||||
|
||||
if (!trailingTrivia) {
|
||||
trailingTrivia = [];
|
||||
}
|
||||
|
||||
trailingTrivia.push(trivia);
|
||||
|
||||
if (currentToken === SyntaxKind.NewLineTrivia) {
|
||||
// move past new line
|
||||
scanner.scan();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return lastTokenInfo = {
|
||||
leadingTrivia: leadingTrivia,
|
||||
trailingTrivia: trailingTrivia,
|
||||
token: token
|
||||
}
|
||||
}
|
||||
|
||||
function isOnToken(): boolean {
|
||||
var current = (lastTokenInfo && lastTokenInfo.token.kind) || scanner.getToken();
|
||||
var startPos = (lastTokenInfo && lastTokenInfo.token.pos) || scanner.getStartPos();
|
||||
return startPos < endPos && current !== SyntaxKind.EndOfFileToken && !isTrivia(current);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
module ts.formatting {
|
||||
|
||||
var internedTabsIndentation: string[];
|
||||
var internedSpacesIndentation: string[];
|
||||
|
||||
export function getIndentationString(indentation: number, options: FormatCodeOptions): string {
|
||||
if (!options.ConvertTabsToSpaces) {
|
||||
var tabs = Math.floor(indentation / options.TabSize);
|
||||
var spaces = indentation - tabs * options.TabSize;
|
||||
|
||||
var tabString: string;
|
||||
if (!internedTabsIndentation) {
|
||||
internedTabsIndentation = [];
|
||||
}
|
||||
|
||||
if (internedTabsIndentation[tabs] === undefined) {
|
||||
internedTabsIndentation[tabs] = tabString = repeat('\t', tabs);
|
||||
}
|
||||
else {
|
||||
tabString = internedTabsIndentation[tabs];
|
||||
}
|
||||
|
||||
return spaces ? tabString + repeat(" ", spaces) : tabString;
|
||||
}
|
||||
else {
|
||||
var spacesString: string;
|
||||
var quotient = Math.floor(indentation / options.IndentSize);
|
||||
var remainder = indentation % options.IndentSize;
|
||||
if (!internedSpacesIndentation) {
|
||||
internedSpacesIndentation = [];
|
||||
}
|
||||
|
||||
if (internedSpacesIndentation[quotient] === undefined) {
|
||||
spacesString = repeat(" ", options.IndentSize * quotient);
|
||||
internedSpacesIndentation[quotient] = spacesString;
|
||||
}
|
||||
else {
|
||||
spacesString = internedSpacesIndentation[quotient];
|
||||
}
|
||||
|
||||
|
||||
return remainder ? spacesString + repeat(" ", remainder) : spacesString;
|
||||
}
|
||||
|
||||
function repeat(value: string, count: number): string {
|
||||
var s = "";
|
||||
for (var i = 0; i < count; ++i) {
|
||||
s += value;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export class IndentationNodeContext {
|
||||
private _node: ISyntaxNode;
|
||||
private _parent: IndentationNodeContext;
|
||||
private _fullStart: number;
|
||||
private _indentationAmount: number;
|
||||
private _childIndentationAmountDelta: number;
|
||||
private _depth: number;
|
||||
private _hasSkippedOrMissingTokenChild: boolean;
|
||||
|
||||
constructor(parent: IndentationNodeContext, node: ISyntaxNode, fullStart: number, indentationAmount: number, childIndentationAmountDelta: number) {
|
||||
this.update(parent, node, fullStart, indentationAmount, childIndentationAmountDelta);
|
||||
}
|
||||
|
||||
public parent(): IndentationNodeContext {
|
||||
return this._parent;
|
||||
}
|
||||
|
||||
public node(): ISyntaxNode {
|
||||
return this._node;
|
||||
}
|
||||
|
||||
public fullStart(): number {
|
||||
return this._fullStart;
|
||||
}
|
||||
|
||||
public fullWidth(): number {
|
||||
return fullWidth(this._node);
|
||||
}
|
||||
|
||||
public start(): number {
|
||||
return this._fullStart + leadingTriviaWidth(this._node);
|
||||
}
|
||||
|
||||
public end(): number {
|
||||
return this._fullStart + leadingTriviaWidth(this._node) + width(this._node);
|
||||
}
|
||||
|
||||
public indentationAmount(): number {
|
||||
return this._indentationAmount;
|
||||
}
|
||||
|
||||
public childIndentationAmountDelta(): number {
|
||||
return this._childIndentationAmountDelta;
|
||||
}
|
||||
|
||||
public depth(): number {
|
||||
return this._depth;
|
||||
}
|
||||
|
||||
public kind(): SyntaxKind {
|
||||
return this._node.kind;
|
||||
}
|
||||
|
||||
public hasSkippedOrMissingTokenChild(): boolean {
|
||||
if (this._hasSkippedOrMissingTokenChild === null) {
|
||||
this._hasSkippedOrMissingTokenChild = Syntax.nodeHasSkippedOrMissingTokens(this._node);
|
||||
}
|
||||
return this._hasSkippedOrMissingTokenChild;
|
||||
}
|
||||
|
||||
public clone(pool: IndentationNodeContextPool): IndentationNodeContext {
|
||||
var parent: IndentationNodeContext = null;
|
||||
if (this._parent) {
|
||||
parent = this._parent.clone(pool);
|
||||
}
|
||||
return pool.getNode(parent, this._node, this._fullStart, this._indentationAmount, this._childIndentationAmountDelta);
|
||||
}
|
||||
|
||||
public update(parent: IndentationNodeContext, node: ISyntaxNode, fullStart: number, indentationAmount: number, childIndentationAmountDelta: number) {
|
||||
this._parent = parent;
|
||||
this._node = node;
|
||||
this._fullStart = fullStart;
|
||||
this._indentationAmount = indentationAmount;
|
||||
this._childIndentationAmountDelta = childIndentationAmountDelta;
|
||||
this._hasSkippedOrMissingTokenChild = null;
|
||||
|
||||
if (parent) {
|
||||
this._depth = parent.depth() + 1;
|
||||
}
|
||||
else {
|
||||
this._depth = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export class IndentationNodeContextPool {
|
||||
private nodes: IndentationNodeContext[] = [];
|
||||
|
||||
public getNode(parent: IndentationNodeContext, node: ISyntaxNode, fullStart: number, indentationLevel: number, childIndentationLevelDelta: number): IndentationNodeContext {
|
||||
if (this.nodes.length > 0) {
|
||||
var cachedNode = this.nodes.pop();
|
||||
cachedNode.update(parent, node, fullStart, indentationLevel, childIndentationLevelDelta);
|
||||
return cachedNode;
|
||||
}
|
||||
|
||||
return new IndentationNodeContext(parent, node, fullStart, indentationLevel, childIndentationLevelDelta);
|
||||
}
|
||||
|
||||
public releaseNode(node: IndentationNodeContext, recursive: boolean = false): void {
|
||||
this.nodes.push(node);
|
||||
|
||||
if (recursive) {
|
||||
var parent = node.parent();
|
||||
if (parent) {
|
||||
this.releaseNode(parent, recursive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,371 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export class IndentationTrackingWalker {
|
||||
private _position: number = 0;
|
||||
private _parent: IndentationNodeContext = null;
|
||||
private _textSpan: TextSpan;
|
||||
private _snapshot: ITextSnapshot;
|
||||
private _lastTriviaWasNewLine: boolean;
|
||||
private _indentationNodeContextPool: IndentationNodeContextPool;
|
||||
private _text: ISimpleText;
|
||||
|
||||
constructor(textSpan: TextSpan, sourceUnit: SourceUnitSyntax, snapshot: ITextSnapshot, indentFirstToken: boolean, public options: FormattingOptions) {
|
||||
// Create a pool object to manage context nodes while walking the tree
|
||||
this._indentationNodeContextPool = new IndentationNodeContextPool();
|
||||
|
||||
this._textSpan = textSpan;
|
||||
this._text = sourceUnit.syntaxTree.text;
|
||||
this._snapshot = snapshot;
|
||||
this._parent = this._indentationNodeContextPool.getNode(null, sourceUnit, 0, 0, 0);
|
||||
|
||||
// Is the first token in the span at the start of a new line.
|
||||
this._lastTriviaWasNewLine = indentFirstToken;
|
||||
}
|
||||
|
||||
public position(): number {
|
||||
return this._position;
|
||||
}
|
||||
|
||||
public parent(): IndentationNodeContext {
|
||||
return this._parent;
|
||||
}
|
||||
|
||||
public textSpan(): TextSpan {
|
||||
return this._textSpan;
|
||||
}
|
||||
|
||||
public snapshot(): ITextSnapshot {
|
||||
return this._snapshot;
|
||||
}
|
||||
|
||||
public indentationNodeContextPool(): IndentationNodeContextPool {
|
||||
return this._indentationNodeContextPool;
|
||||
}
|
||||
|
||||
public forceIndentNextToken(tokenStart: number): void {
|
||||
this._lastTriviaWasNewLine = true;
|
||||
this.forceRecomputeIndentationOfParent(tokenStart, true);
|
||||
}
|
||||
|
||||
public forceSkipIndentingNextToken(tokenStart: number): void {
|
||||
this._lastTriviaWasNewLine = false;
|
||||
this.forceRecomputeIndentationOfParent(tokenStart, false);
|
||||
}
|
||||
|
||||
public indentToken(token: ISyntaxToken, indentationAmount: number, commentIndentationAmount: number): void {
|
||||
throw Errors.abstract();
|
||||
}
|
||||
|
||||
public visitTokenInSpan(token: ISyntaxToken): void {
|
||||
if (this._lastTriviaWasNewLine) {
|
||||
// Compute the indentation level at the current token
|
||||
var indentationAmount = this.getTokenIndentationAmount(token);
|
||||
var commentIndentationAmount = this.getCommentIndentationAmount(token);
|
||||
|
||||
// Process the token
|
||||
this.indentToken(token, indentationAmount, commentIndentationAmount);
|
||||
}
|
||||
}
|
||||
|
||||
public visitToken(token: ISyntaxToken): void {
|
||||
var tokenSpan = new TextSpan(this._position, token.fullWidth());
|
||||
|
||||
if (tokenSpan.intersectsWithTextSpan(this._textSpan)) {
|
||||
this.visitTokenInSpan(token);
|
||||
|
||||
// Only track new lines on tokens within the range. Make sure to check that the last trivia is a newline, and not just one of the trivia
|
||||
var _nextToken = nextToken(token);
|
||||
if (_nextToken && _nextToken.hasLeadingTrivia()) {
|
||||
var trivia = _nextToken.leadingTrivia();
|
||||
this._lastTriviaWasNewLine = trivia.hasNewLine();
|
||||
}
|
||||
else {
|
||||
this._lastTriviaWasNewLine = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the position
|
||||
this._position += token.fullWidth();
|
||||
}
|
||||
|
||||
public walk(element: ISyntaxElement) {
|
||||
if (element) {
|
||||
if (isToken(element)) {
|
||||
this.visitToken(<ISyntaxToken>element);
|
||||
}
|
||||
else if (element.kind === SyntaxKind.List) {
|
||||
for (var i = 0, n = childCount(element); i < n; i++) {
|
||||
this.walk(childAt(element, i));
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.visitNode(<ISyntaxNode>element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private visitNode(node: ISyntaxNode): void {
|
||||
var nodeSpan = new TextSpan(this._position, fullWidth(node));
|
||||
|
||||
if (nodeSpan.intersectsWithTextSpan(this._textSpan)) {
|
||||
// Update indentation level
|
||||
var indentation = this.getNodeIndentation(node);
|
||||
|
||||
// Update the parent
|
||||
var currentParent = this._parent;
|
||||
this._parent = this._indentationNodeContextPool.getNode(currentParent, node, this._position, indentation.indentationAmount, indentation.indentationAmountDelta);
|
||||
|
||||
// Visit node
|
||||
for (var i = 0, n = childCount(node); i < n; i++) {
|
||||
this.walk(childAt(node, i));
|
||||
}
|
||||
|
||||
// Reset state
|
||||
this._indentationNodeContextPool.releaseNode(this._parent);
|
||||
this._parent = currentParent;
|
||||
}
|
||||
else {
|
||||
// We're skipping the node, so update our position accordingly.
|
||||
this._position += fullWidth(node);
|
||||
}
|
||||
}
|
||||
|
||||
private getTokenIndentationAmount(token: ISyntaxToken): number {
|
||||
// If this is the first token of a node, it should follow the node indentation and not the child indentation;
|
||||
// (e.g.class in a class declaration or module in module declariotion).
|
||||
// Open and close braces should follow the indentation of thier parent as well(e.g.
|
||||
// class {
|
||||
// }
|
||||
// Also in a do-while statement, the while should be indented like the parent.
|
||||
if (firstToken(this._parent.node()) === token ||
|
||||
token.kind === SyntaxKind.OpenBraceToken || token.kind === SyntaxKind.CloseBraceToken ||
|
||||
token.kind === SyntaxKind.OpenBracketToken || token.kind === SyntaxKind.CloseBracketToken ||
|
||||
(token.kind === SyntaxKind.WhileKeyword && this._parent.node().kind == SyntaxKind.DoStatement)) {
|
||||
return this._parent.indentationAmount();
|
||||
}
|
||||
|
||||
return (this._parent.indentationAmount() + this._parent.childIndentationAmountDelta());
|
||||
}
|
||||
|
||||
private getCommentIndentationAmount(token: ISyntaxToken): number {
|
||||
// If this is token terminating an indentation scope, leading comments should be indented to follow the children
|
||||
// indentation level and not the node
|
||||
|
||||
if (token.kind === SyntaxKind.CloseBraceToken || token.kind === SyntaxKind.CloseBracketToken) {
|
||||
return (this._parent.indentationAmount() + this._parent.childIndentationAmountDelta());
|
||||
}
|
||||
return this._parent.indentationAmount();
|
||||
}
|
||||
|
||||
private getNodeIndentation(node: ISyntaxNode, newLineInsertedByFormatting?: boolean): { indentationAmount: number; indentationAmountDelta: number; } {
|
||||
var parent = this._parent;
|
||||
|
||||
// We need to get the parent's indentation, which could be one of 2 things. If first token of the parent is in the span, use the parent's computed indentation.
|
||||
// If the parent was outside the span, use the actual indentation of the parent.
|
||||
var parentIndentationAmount: number;
|
||||
if (this._textSpan.containsPosition(parent.start())) {
|
||||
parentIndentationAmount = parent.indentationAmount();
|
||||
}
|
||||
else {
|
||||
if (parent.kind() === SyntaxKind.Block && !this.shouldIndentBlockInParent(this._parent.parent())) {
|
||||
// Blocks preserve the indentation of their containing node (unless they're a
|
||||
// standalone block in a list). i.e. if you have:
|
||||
//
|
||||
// function foo(
|
||||
// a: number) {
|
||||
//
|
||||
// Then we expect the indentation of the block to be tied to the function, not to
|
||||
// the line that the block is defined on. If we were to do the latter, then the
|
||||
// indentation would be here:
|
||||
//
|
||||
// function foo(
|
||||
// a: number) {
|
||||
// |
|
||||
//
|
||||
// Instead of:
|
||||
//
|
||||
// function foo(
|
||||
// a: number) {
|
||||
// |
|
||||
parent = this._parent.parent();
|
||||
}
|
||||
|
||||
var line = this._snapshot.getLineFromPosition(parent.start()).getText();
|
||||
var firstNonWhiteSpacePosition = Indentation.firstNonWhitespacePosition(line);
|
||||
parentIndentationAmount = Indentation.columnForPositionInString(line, firstNonWhiteSpacePosition, this.options);
|
||||
}
|
||||
var parentIndentationAmountDelta = parent.childIndentationAmountDelta();
|
||||
|
||||
// The indentation level of the node
|
||||
var indentationAmount: number;
|
||||
|
||||
// The delta it adds to its children.
|
||||
var indentationAmountDelta: number;
|
||||
var parentNode = parent.node();
|
||||
|
||||
switch (node.kind) {
|
||||
default:
|
||||
// General case
|
||||
// This node should follow the child indentation set by its parent
|
||||
// This node does not introduce any new indentation scope, indent any decendants of this node (tokens or child nodes)
|
||||
// using the same indentation level
|
||||
indentationAmount = (parentIndentationAmount + parentIndentationAmountDelta);
|
||||
indentationAmountDelta = 0;
|
||||
break;
|
||||
|
||||
// Statements introducing {}
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.ObjectType:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
case SyntaxKind.ConstructorDeclaration:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.MemberFunctionDeclaration:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.IndexMemberDeclaration:
|
||||
case SyntaxKind.CatchClause:
|
||||
// Statements introducing []
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
case SyntaxKind.ArrayType:
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
case SyntaxKind.IndexSignature:
|
||||
// Other statements
|
||||
case SyntaxKind.ForStatement:
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.WithStatement:
|
||||
case SyntaxKind.CaseSwitchClause:
|
||||
case SyntaxKind.DefaultSwitchClause:
|
||||
case SyntaxKind.ReturnStatement:
|
||||
case SyntaxKind.ThrowStatement:
|
||||
case SyntaxKind.SimpleArrowFunctionExpression:
|
||||
case SyntaxKind.ParenthesizedArrowFunctionExpression:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.ExportAssignment:
|
||||
|
||||
// Expressions which have argument lists or parameter lists
|
||||
case SyntaxKind.InvocationExpression:
|
||||
case SyntaxKind.ObjectCreationExpression:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
|
||||
// These nodes should follow the child indentation set by its parent;
|
||||
// they introduce a new indenation scope; children should be indented at one level deeper
|
||||
indentationAmount = (parentIndentationAmount + parentIndentationAmountDelta);
|
||||
indentationAmountDelta = this.options.indentSpaces;
|
||||
break;
|
||||
|
||||
case SyntaxKind.IfStatement:
|
||||
if (parent.kind() === SyntaxKind.ElseClause &&
|
||||
!SyntaxUtilities.isLastTokenOnLine((<ElseClauseSyntax>parentNode).elseKeyword, this._text)) {
|
||||
// This is an else if statement with the if on the same line as the else, do not indent the if statmement.
|
||||
// Note: Children indentation has already been set by the parent if statement, so no need to increment
|
||||
indentationAmount = parentIndentationAmount;
|
||||
}
|
||||
else {
|
||||
// Otherwise introduce a new indenation scope; children should be indented at one level deeper
|
||||
indentationAmount = (parentIndentationAmount + parentIndentationAmountDelta);
|
||||
}
|
||||
indentationAmountDelta = this.options.indentSpaces;
|
||||
break;
|
||||
|
||||
case SyntaxKind.ElseClause:
|
||||
// Else should always follow its parent if statement indentation.
|
||||
// Note: Children indentation has already been set by the parent if statement, so no need to increment
|
||||
indentationAmount = parentIndentationAmount;
|
||||
indentationAmountDelta = this.options.indentSpaces;
|
||||
break;
|
||||
|
||||
|
||||
case SyntaxKind.Block:
|
||||
// Check if the block is a member in a list of statements (if the parent is a source unit, module, or block, or switch clause)
|
||||
if (this.shouldIndentBlockInParent(parent)) {
|
||||
indentationAmount = parentIndentationAmount + parentIndentationAmountDelta;
|
||||
}
|
||||
else {
|
||||
indentationAmount = parentIndentationAmount;
|
||||
}
|
||||
|
||||
indentationAmountDelta = this.options.indentSpaces;
|
||||
break;
|
||||
}
|
||||
|
||||
// If the parent happens to start on the same line as this node, then override the current node indenation with that
|
||||
// of the parent. This avoid having to add an extra level of indentation for the children. e.g.:
|
||||
// return {
|
||||
// a:1
|
||||
// };
|
||||
// instead of:
|
||||
// return {
|
||||
// a:1
|
||||
// };
|
||||
// We also need to pass the delta (if it is nonzero) to the children, so that subsequent lines get indented. Essentially, if any node starting on the given line
|
||||
// has a nonzero delta , the resulting delta should be inherited from this node. This is to indent cases like the following:
|
||||
// return a
|
||||
// || b;
|
||||
// Lastly, it is possible the node indentation needs to be recomputed because the formatter inserted a newline before its first token.
|
||||
// If this is the case, we know the node no longer starts on the same line as its parent (or at least we shouldn't treat it as such).
|
||||
if (parentNode) {
|
||||
if (!newLineInsertedByFormatting /*This could be false or undefined here*/) {
|
||||
var parentStartLine = this._snapshot.getLineNumberFromPosition(parent.start());
|
||||
var currentNodeStartLine = this._snapshot.getLineNumberFromPosition(this._position + leadingTriviaWidth(node));
|
||||
if (parentStartLine === currentNodeStartLine || newLineInsertedByFormatting === false /*meaning a new line was removed and we are force recomputing*/) {
|
||||
indentationAmount = parentIndentationAmount;
|
||||
indentationAmountDelta = Math.min(this.options.indentSpaces, parentIndentationAmountDelta + indentationAmountDelta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
indentationAmount: indentationAmount,
|
||||
indentationAmountDelta: indentationAmountDelta
|
||||
};
|
||||
}
|
||||
|
||||
private shouldIndentBlockInParent(parent: IndentationNodeContext): boolean {
|
||||
switch (parent.kind()) {
|
||||
case SyntaxKind.SourceUnit:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.Block:
|
||||
case SyntaxKind.CaseSwitchClause:
|
||||
case SyntaxKind.DefaultSwitchClause:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private forceRecomputeIndentationOfParent(tokenStart: number, newLineAdded: boolean /*as opposed to removed*/): void {
|
||||
var parent = this._parent;
|
||||
if (start(parent.node()) === tokenStart) {
|
||||
// Temporarily pop the parent before recomputing
|
||||
this._parent = parent.parent();
|
||||
var indentation = this.getNodeIndentation(parent.node(), /* newLineInsertedByFormatting */ newLineAdded);
|
||||
parent.update(parent.parent(), parent.node(), parent.fullStart(), indentation.indentationAmount, indentation.indentationAmountDelta);
|
||||
this._parent = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,221 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export class MultipleTokenIndenter extends IndentationTrackingWalker {
|
||||
private _edits: TextEditInfo[] = [];
|
||||
|
||||
constructor(textSpan: TextSpan, sourceUnit: SourceUnitSyntax, snapshot: ITextSnapshot, indentFirstToken: boolean, options: FormattingOptions) {
|
||||
super(textSpan, sourceUnit, snapshot, indentFirstToken, options);
|
||||
}
|
||||
|
||||
public indentToken(token: ISyntaxToken, indentationAmount: number, commentIndentationAmount: number): void {
|
||||
// Ignore generated tokens
|
||||
if (token.fullWidth() === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have any skipped tokens as children, do not process this node for indentation or formatting
|
||||
if (this.parent().hasSkippedOrMissingTokenChild()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Be strict, and only consider nodes that fall inside the span. This avoids indenting a multiline string
|
||||
// on enter at the end of, as the whole token was not included in the span
|
||||
var tokenSpan = new TextSpan(this.position() + token.leadingTriviaWidth(), width(token));
|
||||
if (!this.textSpan().containsTextSpan(tokenSpan)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute an indentation string for this token
|
||||
var indentationString = Indentation.indentationString(indentationAmount, this.options);
|
||||
|
||||
var commentIndentationString = Indentation.indentationString(commentIndentationAmount, this.options);
|
||||
|
||||
// Record any needed indentation edits
|
||||
this.recordIndentationEditsForToken(token, indentationString, commentIndentationString);
|
||||
}
|
||||
|
||||
public edits(): TextEditInfo[]{
|
||||
return this._edits;
|
||||
}
|
||||
|
||||
public recordEdit(position: number, length: number, replaceWith: string): void {
|
||||
this._edits.push(new TextEditInfo(position, length, replaceWith));
|
||||
}
|
||||
|
||||
private recordIndentationEditsForToken(token: ISyntaxToken, indentationString: string, commentIndentationString: string) {
|
||||
var position = this.position();
|
||||
var indentNextTokenOrTrivia = true;
|
||||
var leadingWhiteSpace = ""; // We need to track the whitespace before a multiline comment
|
||||
|
||||
// Process any leading trivia if any
|
||||
var triviaList = token.leadingTrivia();
|
||||
if (triviaList) {
|
||||
var seenNewLine = position === 0;
|
||||
|
||||
for (var i = 0, length = triviaList.count(); i < length; i++, position += trivia.fullWidth()) {
|
||||
var trivia = triviaList.syntaxTriviaAt(i);
|
||||
|
||||
// Skip all trivia up to the first newline we see. We consider this trivia to
|
||||
// 'belong' to the previous token.
|
||||
if (!seenNewLine) {
|
||||
if (trivia.kind !== SyntaxKind.NewLineTrivia) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
seenNewLine = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip this trivia if it is not in the span
|
||||
if (!this.textSpan().containsTextSpan(new TextSpan(position, trivia.fullWidth()))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (trivia.kind) {
|
||||
case SyntaxKind.MultiLineCommentTrivia:
|
||||
// We will only indent the first line of the multiline comment if we were planning to indent the next trivia. However,
|
||||
// subsequent lines will always be indented
|
||||
this.recordIndentationEditsForMultiLineComment(trivia, position, commentIndentationString, leadingWhiteSpace, !indentNextTokenOrTrivia /* already indented first line */);
|
||||
indentNextTokenOrTrivia = false;
|
||||
leadingWhiteSpace = "";
|
||||
break;
|
||||
|
||||
case SyntaxKind.SingleLineCommentTrivia:
|
||||
case SyntaxKind.SkippedTokenTrivia:
|
||||
if (indentNextTokenOrTrivia) {
|
||||
this.recordIndentationEditsForSingleLineOrSkippedText(trivia, position, commentIndentationString);
|
||||
indentNextTokenOrTrivia = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.WhitespaceTrivia:
|
||||
// If the next trivia is a comment, use the comment indentation level instead of the regular indentation level
|
||||
// If the next trivia is a newline, this whole line is just whitespace, so don't do anything (trimming will take care of it)
|
||||
var nextTrivia = length > i + 1 && triviaList.syntaxTriviaAt(i + 1);
|
||||
var whiteSpaceIndentationString = nextTrivia && nextTrivia.isComment() ? commentIndentationString : indentationString;
|
||||
if (indentNextTokenOrTrivia) {
|
||||
if (!(nextTrivia && nextTrivia.isNewLine())) {
|
||||
this.recordIndentationEditsForWhitespace(trivia, position, whiteSpaceIndentationString);
|
||||
}
|
||||
indentNextTokenOrTrivia = false;
|
||||
}
|
||||
leadingWhiteSpace += trivia.fullText();
|
||||
break;
|
||||
|
||||
case SyntaxKind.NewLineTrivia:
|
||||
// We hit a newline processing the trivia. We need to add the indentation to the
|
||||
// next line as well. Note: don't bother indenting the newline itself. This will
|
||||
// just insert ugly whitespace that most users probably will not want.
|
||||
indentNextTokenOrTrivia = true;
|
||||
leadingWhiteSpace = "";
|
||||
break;
|
||||
|
||||
default:
|
||||
throw Errors.invalidOperation();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (token.kind !== SyntaxKind.EndOfFileToken && indentNextTokenOrTrivia) {
|
||||
// If the last trivia item was a new line, or no trivia items were encounterd record the
|
||||
// indentation edit at the token position
|
||||
if (indentationString.length > 0) {
|
||||
this.recordEdit(position, 0, indentationString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private recordIndentationEditsForSingleLineOrSkippedText(trivia: ISyntaxTrivia, fullStart: number, indentationString: string): void {
|
||||
// Record the edit
|
||||
if (indentationString.length > 0) {
|
||||
this.recordEdit(fullStart, 0, indentationString);
|
||||
}
|
||||
}
|
||||
|
||||
private recordIndentationEditsForWhitespace(trivia: ISyntaxTrivia, fullStart: number, indentationString: string): void {
|
||||
var text = trivia.fullText();
|
||||
|
||||
// Check if the current indentation matches the desired indentation or not
|
||||
if (indentationString === text) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Record the edit
|
||||
this.recordEdit(fullStart, text.length, indentationString);
|
||||
}
|
||||
|
||||
private recordIndentationEditsForMultiLineComment(trivia: ISyntaxTrivia, fullStart: number, indentationString: string, leadingWhiteSpace: string, firstLineAlreadyIndented: boolean): void {
|
||||
// If the multiline comment spans multiple lines, we need to add the right indent amount to
|
||||
// each successive line segment as well.
|
||||
var position = fullStart;
|
||||
var segments = Syntax.splitMultiLineCommentTriviaIntoMultipleLines(trivia);
|
||||
|
||||
if (segments.length <= 1) {
|
||||
if (!firstLineAlreadyIndented) {
|
||||
// Process the one-line multiline comment just like a single line comment
|
||||
this.recordIndentationEditsForSingleLineOrSkippedText(trivia, fullStart, indentationString);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Find number of columns in first segment
|
||||
var whiteSpaceColumnsInFirstSegment = Indentation.columnForPositionInString(leadingWhiteSpace, leadingWhiteSpace.length, this.options);
|
||||
|
||||
var indentationColumns = Indentation.columnForPositionInString(indentationString, indentationString.length, this.options);
|
||||
var startIndex = 0;
|
||||
if (firstLineAlreadyIndented) {
|
||||
startIndex = 1;
|
||||
position += segments[0].length;
|
||||
}
|
||||
for (var i = startIndex; i < segments.length; i++) {
|
||||
var segment = segments[i];
|
||||
this.recordIndentationEditsForSegment(segment, position, indentationColumns, whiteSpaceColumnsInFirstSegment);
|
||||
position += segment.length;
|
||||
}
|
||||
}
|
||||
|
||||
private recordIndentationEditsForSegment(segment: string, fullStart: number, indentationColumns: number, whiteSpaceColumnsInFirstSegment: number): void {
|
||||
// Indent subsequent lines using a column delta of the actual indentation relative to the first line
|
||||
var firstNonWhitespacePosition = Indentation.firstNonWhitespacePosition(segment);
|
||||
var leadingWhiteSpaceColumns = Indentation.columnForPositionInString(segment, firstNonWhitespacePosition, this.options);
|
||||
var deltaFromFirstSegment = leadingWhiteSpaceColumns - whiteSpaceColumnsInFirstSegment;
|
||||
var finalColumns = indentationColumns + deltaFromFirstSegment;
|
||||
if (finalColumns < 0) {
|
||||
finalColumns = 0;
|
||||
}
|
||||
var indentationString = Indentation.indentationString(finalColumns, this.options);
|
||||
|
||||
if (firstNonWhitespacePosition < segment.length &&
|
||||
CharacterInfo.isLineTerminator(segment.charCodeAt(firstNonWhitespacePosition))) {
|
||||
// If this segment was just a newline, then don't bother indenting it. That will just
|
||||
// leave the user with an ugly indent in their output that they probably do not want.
|
||||
return;
|
||||
}
|
||||
|
||||
if (indentationString === segment.substring(0, firstNonWhitespacePosition)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Record the edit
|
||||
this.recordEdit(fullStart, firstNonWhitespacePosition, indentationString);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,12 +13,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='..\text.ts' />
|
||||
///<reference path='..\services.ts' />
|
||||
///<reference path='textSnapshot.ts' />
|
||||
///<reference path='textSnapshotLine.ts' />
|
||||
///<reference path='snapshotPoint.ts' />
|
||||
///<reference path='formattingContext.ts' />
|
||||
///<reference path='formattingManager.ts' />
|
||||
///<reference path='formattingRequestKind.ts' />
|
||||
///<reference path='rule.ts' />
|
||||
///<reference path='ruleAction.ts' />
|
||||
@@ -28,12 +25,5 @@
|
||||
///<reference path='ruleOperationContext.ts' />
|
||||
///<reference path='rules.ts' />
|
||||
///<reference path='rulesMap.ts' />
|
||||
///<reference path='rulesProvider.ts' />
|
||||
///<reference path='textEditInfo.ts' />
|
||||
///<reference path='tokenRange.ts' />
|
||||
///<reference path='tokenSpan.ts' />
|
||||
///<reference path='indentationNodeContext.ts' />
|
||||
///<reference path='indentationNodeContextPool.ts' />
|
||||
///<reference path='indentationTrackingWalker.ts' />
|
||||
///<reference path='multipleTokenIndenter.ts' />
|
||||
///<reference path='formatter.ts' />
|
||||
///<reference path='tokenSpan.ts' />
|
||||
@@ -13,9 +13,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
module ts.formatting {
|
||||
export class Rule {
|
||||
constructor(
|
||||
public Descriptor: RuleDescriptor,
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export enum RuleAction {
|
||||
Ignore,
|
||||
Space,
|
||||
NewLine,
|
||||
Delete
|
||||
module ts.formatting {
|
||||
export const enum RuleAction {
|
||||
Ignore = 0x00000001,
|
||||
Space = 0x00000002,
|
||||
NewLine = 0x00000004,
|
||||
Delete = 0x00000008
|
||||
}
|
||||
}
|
||||
@@ -13,9 +13,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
module ts.formatting {
|
||||
export class RuleDescriptor {
|
||||
constructor(public LeftTokenRange: Shared.TokenRange, public RightTokenRange: Shared.TokenRange) {
|
||||
}
|
||||
@@ -34,7 +34,6 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
static create3(left: SyntaxKind, right: Shared.TokenRange): RuleDescriptor
|
||||
//: this(TokenRange.FromToken(left), right)
|
||||
{
|
||||
return RuleDescriptor.create4(Shared.TokenRange.FromToken(left), right);
|
||||
}
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export enum RuleFlags {
|
||||
module ts.formatting {
|
||||
export const enum RuleFlags {
|
||||
None,
|
||||
CanDeleteNewLines
|
||||
}
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
module ts.formatting {
|
||||
export class RuleOperation {
|
||||
public Context: RuleOperationContext;
|
||||
public Action: RuleAction;
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
module ts.formatting {
|
||||
|
||||
export class RuleOperationContext {
|
||||
private customContextChecks: { (context: FormattingContext): boolean; }[];
|
||||
|
||||
@@ -13,9 +13,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
module ts.formatting {
|
||||
export class Rules {
|
||||
public getRuleName(rule: Rule) {
|
||||
var o: ts.Map<any> = <any>this;
|
||||
@@ -24,7 +24,7 @@ module TypeScript.Services.Formatting {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
throw new Error(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.Unknown_rule, null));
|
||||
throw new Error("Unknown rule");
|
||||
}
|
||||
|
||||
[name: string]: any;
|
||||
@@ -241,7 +241,7 @@ module TypeScript.Services.Formatting {
|
||||
this.SpaceBeforeOpenBraceInFunction = new Rule(RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);
|
||||
|
||||
// Place a space before open brace in a TypeScript declaration that has braces as children (class, module, enum, etc)
|
||||
this.TypeScriptOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.MultiLineCommentTrivia]);
|
||||
this.TypeScriptOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.MultiLineCommentTrivia]);
|
||||
this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock = new Rule(RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsTypeScriptDeclWithBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);
|
||||
|
||||
// Place a space before open brace in a control flow construct
|
||||
@@ -299,7 +299,7 @@ module TypeScript.Services.Formatting {
|
||||
|
||||
// get x() {}
|
||||
// set x(val) {}
|
||||
this.SpaceAfterGetSetInMember = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.GetKeyword, SyntaxKind.SetKeyword]), SyntaxKind.IdentifierName), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space));
|
||||
this.SpaceAfterGetSetInMember = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.GetKeyword, SyntaxKind.SetKeyword]), SyntaxKind.Identifier), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space));
|
||||
|
||||
// Special case for binary operators (that are keywords). For these we have to add a space and shouldn't follow any user options.
|
||||
this.SpaceBeforeBinaryKeywordOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryKeywordOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
|
||||
@@ -324,7 +324,7 @@ module TypeScript.Services.Formatting {
|
||||
this.SpaceAfterArrow = new Rule(RuleDescriptor.create3(SyntaxKind.EqualsGreaterThanToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
|
||||
|
||||
// Optional parameters and var args
|
||||
this.NoSpaceAfterEllipsis = new Rule(RuleDescriptor.create1(SyntaxKind.DotDotDotToken, SyntaxKind.IdentifierName), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
|
||||
this.NoSpaceAfterEllipsis = new Rule(RuleDescriptor.create1(SyntaxKind.DotDotDotToken, SyntaxKind.Identifier), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
|
||||
this.NoSpaceAfterOptionalParameters = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.CommaToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete));
|
||||
|
||||
// generics
|
||||
@@ -437,7 +437,7 @@ module TypeScript.Services.Formatting {
|
||||
///
|
||||
|
||||
static IsForContext(context: FormattingContext): boolean {
|
||||
return context.contextNode.kind() === SyntaxKind.ForStatement;
|
||||
return context.contextNode.kind === SyntaxKind.ForStatement;
|
||||
}
|
||||
|
||||
static IsNotForContext(context: FormattingContext): boolean {
|
||||
@@ -446,8 +446,7 @@ module TypeScript.Services.Formatting {
|
||||
|
||||
static IsBinaryOpContext(context: FormattingContext): boolean {
|
||||
|
||||
switch (context.contextNode.kind()) {
|
||||
// binary expressions
|
||||
switch (context.contextNode.kind) {
|
||||
case SyntaxKind.BinaryExpression:
|
||||
case SyntaxKind.ConditionalExpression:
|
||||
return true;
|
||||
@@ -455,8 +454,11 @@ module TypeScript.Services.Formatting {
|
||||
// equal in import a = module('a');
|
||||
case SyntaxKind.ImportDeclaration:
|
||||
// equal in var a = 0;
|
||||
case SyntaxKind.VariableDeclarator:
|
||||
case SyntaxKind.EqualsValueClause:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
// equal in p = 0;
|
||||
case SyntaxKind.Parameter:
|
||||
case SyntaxKind.EnumMember:
|
||||
case SyntaxKind.Property:
|
||||
return context.currentTokenSpan.kind === SyntaxKind.EqualsToken || context.nextTokenSpan.kind === SyntaxKind.EqualsToken;
|
||||
// "in" keyword in for (var x in []) { }
|
||||
case SyntaxKind.ForInStatement:
|
||||
@@ -512,16 +514,21 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
// IMPORTANT!!! This method must return true ONLY for nodes with open and close braces as immediate children
|
||||
static NodeIsBlockContext(node: IndentationNodeContext): boolean {
|
||||
static NodeIsBlockContext(node: Node): boolean {
|
||||
if (Rules.NodeIsTypeScriptDeclWithBlockContext(node)) {
|
||||
// This means we are in a context that looks like a block to the user, but in the grammar is actually not a node (it's a class, module, enum, object type literal, etc).
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (node.kind()) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Block:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
case SyntaxKind.ObjectLiteral:
|
||||
case SyntaxKind.TryBlock:
|
||||
case SyntaxKind.CatchBlock:
|
||||
case SyntaxKind.FinallyBlock:
|
||||
case SyntaxKind.FunctionBlock:
|
||||
case SyntaxKind.ModuleBlock:
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -529,17 +536,20 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
static IsFunctionDeclContext(context: FormattingContext): boolean {
|
||||
switch (context.contextNode.kind()) {
|
||||
switch (context.contextNode.kind) {
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.MemberFunctionDeclaration:
|
||||
case SyntaxKind.Method:
|
||||
//case SyntaxKind.MemberFunctionDeclaration:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.MethodSignature:
|
||||
///case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ConstructorDeclaration:
|
||||
case SyntaxKind.SimpleArrowFunctionExpression:
|
||||
case SyntaxKind.ParenthesizedArrowFunctionExpression:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
//case SyntaxKind.ConstructorDeclaration:
|
||||
//case SyntaxKind.SimpleArrowFunctionExpression:
|
||||
//case SyntaxKind.ParenthesizedArrowFunctionExpression:
|
||||
case SyntaxKind.InterfaceDeclaration: // This one is not truly a function, but for formatting purposes, it acts just like one
|
||||
return true;
|
||||
}
|
||||
@@ -551,11 +561,12 @@ module TypeScript.Services.Formatting {
|
||||
return Rules.NodeIsTypeScriptDeclWithBlockContext(context.contextNode);
|
||||
}
|
||||
|
||||
static NodeIsTypeScriptDeclWithBlockContext(node: IndentationNodeContext): boolean {
|
||||
switch (node.kind()) {
|
||||
static NodeIsTypeScriptDeclWithBlockContext(node: Node): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.ObjectType:
|
||||
case SyntaxKind.TypeLiteral:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
return true;
|
||||
}
|
||||
@@ -564,11 +575,16 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
static IsAfterCodeBlockContext(context: FormattingContext): boolean {
|
||||
switch (context.currentTokenParent.kind()) {
|
||||
switch (context.currentTokenParent.kind) {
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
case SyntaxKind.Block:
|
||||
case SyntaxKind.TryBlock:
|
||||
case SyntaxKind.CatchBlock:
|
||||
case SyntaxKind.FinallyBlock:
|
||||
case SyntaxKind.FunctionBlock:
|
||||
case SyntaxKind.ModuleBlock:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
return true;
|
||||
}
|
||||
@@ -576,7 +592,7 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
static IsControlDeclContext(context: FormattingContext): boolean {
|
||||
switch (context.contextNode.kind()) {
|
||||
switch (context.contextNode.kind) {
|
||||
case SyntaxKind.IfStatement:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
case SyntaxKind.ForStatement:
|
||||
@@ -585,9 +601,10 @@ module TypeScript.Services.Formatting {
|
||||
case SyntaxKind.TryStatement:
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.WithStatement:
|
||||
case SyntaxKind.ElseClause:
|
||||
case SyntaxKind.CatchClause:
|
||||
case SyntaxKind.FinallyClause:
|
||||
// TODO
|
||||
// case SyntaxKind.ElseClause:
|
||||
case SyntaxKind.CatchBlock:
|
||||
case SyntaxKind.FinallyBlock:
|
||||
return true;
|
||||
|
||||
default:
|
||||
@@ -596,15 +613,15 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
static IsObjectContext(context: FormattingContext): boolean {
|
||||
return context.contextNode.kind() === SyntaxKind.ObjectLiteralExpression;
|
||||
return context.contextNode.kind === SyntaxKind.ObjectLiteral;
|
||||
}
|
||||
|
||||
static IsFunctionCallContext(context: FormattingContext): boolean {
|
||||
return context.contextNode.kind() === SyntaxKind.InvocationExpression;
|
||||
return context.contextNode.kind === SyntaxKind.CallExpression;
|
||||
}
|
||||
|
||||
static IsNewContext(context: FormattingContext): boolean {
|
||||
return context.contextNode.kind() === SyntaxKind.ObjectCreationExpression;
|
||||
return context.contextNode.kind === SyntaxKind.NewExpression;
|
||||
}
|
||||
|
||||
static IsFunctionCallOrNewContext(context: FormattingContext): boolean {
|
||||
@@ -620,25 +637,43 @@ module TypeScript.Services.Formatting {
|
||||
}
|
||||
|
||||
static IsModuleDeclContext(context: FormattingContext): boolean {
|
||||
return context.contextNode.kind() === SyntaxKind.ModuleDeclaration;
|
||||
return context.contextNode.kind === SyntaxKind.ModuleDeclaration;
|
||||
}
|
||||
|
||||
static IsObjectTypeContext(context: FormattingContext): boolean {
|
||||
return context.contextNode.kind() === SyntaxKind.ObjectType && context.contextNode.parent().kind() !== SyntaxKind.InterfaceDeclaration;
|
||||
return context.contextNode.kind === SyntaxKind.TypeLiteral;// && context.contextNode.parent.kind !== SyntaxKind.InterfaceDeclaration;
|
||||
}
|
||||
|
||||
static IsTypeArgumentOrParameter(tokenKind: SyntaxKind, parentKind: SyntaxKind): boolean {
|
||||
return ((tokenKind === SyntaxKind.LessThanToken || tokenKind === SyntaxKind.GreaterThanToken) &&
|
||||
(parentKind === SyntaxKind.TypeParameterList || parentKind === SyntaxKind.TypeArgumentList));
|
||||
static IsTypeArgumentOrParameter(token: TextRangeWithKind, parent: Node): boolean {
|
||||
if (token.kind !== SyntaxKind.LessThanToken && token.kind !== SyntaxKind.GreaterThanToken) {
|
||||
return false;
|
||||
}
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.TypeReference:
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.CallExpression:
|
||||
case SyntaxKind.NewExpression:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static IsTypeArgumentOrParameterContext(context: FormattingContext): boolean {
|
||||
return Rules.IsTypeArgumentOrParameter(context.currentTokenSpan.kind, context.currentTokenParent.kind()) ||
|
||||
Rules.IsTypeArgumentOrParameter(context.nextTokenSpan.kind, context.nextTokenParent.kind());
|
||||
return Rules.IsTypeArgumentOrParameter(context.currentTokenSpan, context.currentTokenParent) ||
|
||||
Rules.IsTypeArgumentOrParameter(context.nextTokenSpan, context.nextTokenParent);
|
||||
}
|
||||
|
||||
static IsVoidOpContext(context: FormattingContext): boolean {
|
||||
return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword && context.currentTokenParent.kind() === SyntaxKind.VoidExpression;
|
||||
return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword && context.currentTokenParent.kind === SyntaxKind.PrefixOperator;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,9 +13,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
module ts.formatting {
|
||||
export class RulesMap {
|
||||
public map: RulesBucket[];
|
||||
public mapRowLength: number;
|
||||
|
||||
@@ -13,16 +13,16 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
/// <reference path="formatting.ts"/>
|
||||
/// <reference path="references.ts"/>
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
module ts.formatting {
|
||||
export class RulesProvider {
|
||||
private globalRules: Rules;
|
||||
private options: ts.FormatCodeOptions;
|
||||
private activeRules: Rule[];
|
||||
private rulesMap: RulesMap;
|
||||
|
||||
constructor(private logger: TypeScript.Logger) {
|
||||
constructor(private logger: Logger) {
|
||||
this.globalRules = new Rules();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
|
||||
export class SnapshotPoint {
|
||||
constructor(public snapshot: ITextSnapshot, public position: number) {
|
||||
}
|
||||
public getContainingLine(): ITextSnapshotLine {
|
||||
return this.snapshot.getLineFromPosition(this.position);
|
||||
}
|
||||
public add(offset: number): SnapshotPoint {
|
||||
return new SnapshotPoint(this.snapshot, this.position + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export class TextEditInfo {
|
||||
|
||||
constructor(public position: number, public length: number, public replaceWith: string) {
|
||||
}
|
||||
|
||||
public toString() {
|
||||
return "[ position: " + this.position + ", length: " + this.length + ", replaceWith: '" + this.replaceWith + "' ]";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export interface ITextSnapshot {
|
||||
getLength(): number;
|
||||
getText(span: TextSpan): string;
|
||||
getLineNumberFromPosition(position: number): number;
|
||||
getLineFromPosition(position: number): ITextSnapshotLine;
|
||||
getLineFromLineNumber(lineNumber: number): ITextSnapshotLine;
|
||||
}
|
||||
|
||||
export class TextSnapshot implements ITextSnapshot {
|
||||
private lines: TextSnapshotLine[];
|
||||
|
||||
constructor(private snapshot: ISimpleText) {
|
||||
this.lines = [];
|
||||
}
|
||||
|
||||
public getLength(): number {
|
||||
return this.snapshot.length();
|
||||
}
|
||||
|
||||
public getText(span: TextSpan): string {
|
||||
return this.snapshot.substr(span.start(), span.length());
|
||||
}
|
||||
|
||||
public getLineNumberFromPosition(position: number): number {
|
||||
return this.snapshot.lineMap().getLineNumberFromPosition(position);
|
||||
}
|
||||
|
||||
public getLineFromPosition(position: number): ITextSnapshotLine {
|
||||
var lineNumber = this.getLineNumberFromPosition(position);
|
||||
return this.getLineFromLineNumber(lineNumber);
|
||||
}
|
||||
|
||||
public getLineFromLineNumber(lineNumber: number): ITextSnapshotLine {
|
||||
var line = this.lines[lineNumber];
|
||||
if (line === undefined) {
|
||||
line = <TextSnapshotLine>this.getLineFromLineNumberWorker(lineNumber);
|
||||
this.lines[lineNumber] = line;
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
private getLineFromLineNumberWorker(lineNumber: number): ITextSnapshotLine {
|
||||
var lineMap = this.snapshot.lineMap().lineStarts();
|
||||
var lineMapIndex = lineNumber; //Note: lineMap is 0-based
|
||||
if (lineMapIndex < 0 || lineMapIndex >= lineMap.length)
|
||||
throw new Error(TypeScript.getDiagnosticMessage(TypeScript.DiagnosticCode.Invalid_line_number_0, [lineMapIndex]));
|
||||
var start = lineMap[lineMapIndex];
|
||||
|
||||
var end: number;
|
||||
var endIncludingLineBreak: number;
|
||||
var lineBreak = "";
|
||||
if (lineMapIndex == lineMap.length) {
|
||||
end = endIncludingLineBreak = this.snapshot.length();
|
||||
}
|
||||
else {
|
||||
endIncludingLineBreak = (lineMapIndex >= lineMap.length - 1 ? this.snapshot.length() : lineMap[lineMapIndex + 1]);
|
||||
for (var p = endIncludingLineBreak - 1; p >= start; p--) {
|
||||
var c = this.snapshot.substr(p, 1);
|
||||
//TODO: Other ones?
|
||||
if (c != "\r" && c != "\n") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
end = p + 1;
|
||||
lineBreak = this.snapshot.substr(end, endIncludingLineBreak - end);
|
||||
}
|
||||
var result = new TextSnapshotLine(this, lineNumber, start, end, lineBreak);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
export interface ITextSnapshotLine {
|
||||
snapshot(): ITextSnapshot;
|
||||
|
||||
start(): SnapshotPoint;
|
||||
startPosition(): number;
|
||||
|
||||
end(): SnapshotPoint;
|
||||
endPosition(): number;
|
||||
|
||||
endIncludingLineBreak(): SnapshotPoint;
|
||||
endIncludingLineBreakPosition(): number;
|
||||
|
||||
length(): number;
|
||||
lineNumber(): number;
|
||||
getText(): string;
|
||||
}
|
||||
|
||||
export class TextSnapshotLine implements ITextSnapshotLine {
|
||||
constructor(private _snapshot: ITextSnapshot, private _lineNumber: number, private _start: number, private _end: number, private _lineBreak: string) {
|
||||
}
|
||||
|
||||
public snapshot() {
|
||||
return this._snapshot;
|
||||
}
|
||||
|
||||
public start() {
|
||||
return new SnapshotPoint(this._snapshot, this._start);
|
||||
}
|
||||
|
||||
public startPosition() {
|
||||
return this._start;
|
||||
}
|
||||
|
||||
public end() {
|
||||
return new SnapshotPoint(this._snapshot, this._end);
|
||||
}
|
||||
|
||||
public endPosition() {
|
||||
return this._end;
|
||||
}
|
||||
|
||||
public endIncludingLineBreak() {
|
||||
return new SnapshotPoint(this._snapshot, this._end + this._lineBreak.length);
|
||||
}
|
||||
|
||||
public endIncludingLineBreakPosition() {
|
||||
return this._end + this._lineBreak.length;
|
||||
}
|
||||
|
||||
public length() {
|
||||
return this._end - this._start;
|
||||
}
|
||||
|
||||
public lineNumber() {
|
||||
return this._lineNumber;
|
||||
}
|
||||
|
||||
public getText(): string {
|
||||
return this._snapshot.getText(TextSpan.fromBounds(this._start, this._end));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,9 +13,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
module ts.formatting {
|
||||
export module Shared {
|
||||
export interface ITokenAccess {
|
||||
GetTokens(): SyntaxKind[];
|
||||
@@ -41,12 +41,6 @@ module TypeScript.Services.Formatting {
|
||||
public Contains(token: SyntaxKind): boolean {
|
||||
return this.tokens.indexOf(token) >= 0;
|
||||
}
|
||||
|
||||
|
||||
public toString(): string {
|
||||
return "[tokenRangeStart=" + SyntaxKind[this.tokens[0]] + "," +
|
||||
"tokenRangeEnd=" + SyntaxKind[this.tokens[this.tokens.length - 1]] + "]";
|
||||
}
|
||||
}
|
||||
|
||||
export class TokenValuesAccess implements ITokenAccess {
|
||||
@@ -76,10 +70,6 @@ module TypeScript.Services.Formatting {
|
||||
public Contains(tokenValue: SyntaxKind): boolean {
|
||||
return tokenValue == this.token;
|
||||
}
|
||||
|
||||
public toString(): string {
|
||||
return "[singleTokenKind=" + SyntaxKind[this.token] + "]";
|
||||
}
|
||||
}
|
||||
|
||||
export class TokenAllAccess implements ITokenAccess {
|
||||
@@ -135,18 +125,18 @@ module TypeScript.Services.Formatting {
|
||||
static Any: TokenRange = TokenRange.AllTokens();
|
||||
static AnyIncludingMultilineComments = TokenRange.FromTokens(TokenRange.Any.GetTokens().concat([SyntaxKind.MultiLineCommentTrivia]));
|
||||
static Keywords = TokenRange.FromRange(SyntaxKind.FirstKeyword, SyntaxKind.LastKeyword);
|
||||
static Operators = TokenRange.FromRange(SyntaxKind.SemicolonToken, SyntaxKind.SlashEqualsToken);
|
||||
static BinaryOperators = TokenRange.FromRange(SyntaxKind.LessThanToken, SyntaxKind.SlashEqualsToken);
|
||||
static Operators = TokenRange.FromRange(SyntaxKind.FirstOperator, SyntaxKind.LastOperator);
|
||||
static BinaryOperators = TokenRange.FromRange(SyntaxKind.FirstBinaryOperator, SyntaxKind.LastBinaryOperator);
|
||||
static BinaryKeywordOperators = TokenRange.FromTokens([SyntaxKind.InKeyword, SyntaxKind.InstanceOfKeyword]);
|
||||
static ReservedKeywords = TokenRange.FromRange(SyntaxKind.FirstFutureReservedStrictKeyword, SyntaxKind.LastFutureReservedStrictKeyword);
|
||||
static ReservedKeywords = TokenRange.FromRange(SyntaxKind.FirstFutureReservedWord, SyntaxKind.LastFutureReservedWord);
|
||||
static UnaryPrefixOperators = TokenRange.FromTokens([SyntaxKind.PlusPlusToken, SyntaxKind.MinusMinusToken, SyntaxKind.TildeToken, SyntaxKind.ExclamationToken]);
|
||||
static UnaryPrefixExpressions = TokenRange.FromTokens([SyntaxKind.NumericLiteral, SyntaxKind.IdentifierName, SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.OpenBraceToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
||||
static UnaryPreincrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
||||
static UnaryPostincrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
|
||||
static UnaryPredecrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
||||
static UnaryPostdecrementExpressions = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
|
||||
static UnaryPrefixExpressions = TokenRange.FromTokens([SyntaxKind.NumericLiteral, SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.OpenBraceToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
||||
static UnaryPreincrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
||||
static UnaryPostincrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
|
||||
static UnaryPredecrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword]);
|
||||
static UnaryPostdecrementExpressions = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword]);
|
||||
static Comments = TokenRange.FromTokens([SyntaxKind.SingleLineCommentTrivia, SyntaxKind.MultiLineCommentTrivia]);
|
||||
static TypeNames = TokenRange.FromTokens([SyntaxKind.IdentifierName, SyntaxKind.NumberKeyword, SyntaxKind.StringKeyword, SyntaxKind.BooleanKeyword, SyntaxKind.VoidKeyword, SyntaxKind.AnyKeyword]);
|
||||
static TypeNames = TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.NumberKeyword, SyntaxKind.StringKeyword, SyntaxKind.BooleanKeyword, SyntaxKind.VoidKeyword, SyntaxKind.AnyKeyword]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,10 +13,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
///<reference path='formatting.ts' />
|
||||
///<reference path='references.ts' />
|
||||
|
||||
|
||||
module TypeScript.Services.Formatting {
|
||||
module ts.formatting {
|
||||
export class TokenSpan extends TextSpan {
|
||||
constructor(public kind: SyntaxKind, start: number, length: number) {
|
||||
super(start, length);
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
|
||||
module TypeScript.Indentation {
|
||||
// Returns the column that this input string ends at (assuming it starts at column 0).
|
||||
export function columnForPositionInString(input: string, position: number, options: FormattingOptions): number {
|
||||
return columnForPositionInStringWorker(input, position, 0, options);
|
||||
}
|
||||
|
||||
function columnForPositionInStringWorker(input: string, position: number, startColumn: number, options: FormattingOptions): number {
|
||||
var column = startColumn;
|
||||
var spacesPerTab = options.spacesPerTab;
|
||||
|
||||
for (var j = 0; j < position; j++) {
|
||||
var ch = input.charCodeAt(j);
|
||||
|
||||
if (ch === CharacterCodes.tab) {
|
||||
column += spacesPerTab - column % spacesPerTab;
|
||||
}
|
||||
else {
|
||||
column++;
|
||||
}
|
||||
}
|
||||
|
||||
return column;
|
||||
}
|
||||
|
||||
export function indentationString(column: number, options: FormattingOptions): string {
|
||||
var numberOfTabs = 0;
|
||||
var numberOfSpaces = Math.max(0, column);
|
||||
|
||||
if (options.useTabs) {
|
||||
numberOfTabs = Math.floor(column / options.spacesPerTab);
|
||||
numberOfSpaces -= numberOfTabs * options.spacesPerTab;
|
||||
}
|
||||
|
||||
return StringUtilities.repeat('\t', numberOfTabs) +
|
||||
StringUtilities.repeat(' ', numberOfSpaces);
|
||||
}
|
||||
|
||||
export function firstNonWhitespacePosition(value: string): number {
|
||||
for (var i = 0; i < value.length; i++) {
|
||||
var ch = value.charCodeAt(i);
|
||||
if (!CharacterInfo.isWhitespace(ch)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return value.length;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
/// <reference path='services.ts' />
|
||||
/// <reference path="text/textSpan.ts" />
|
||||
|
||||
module ts.NavigationBar {
|
||||
export function getNavigationBarItems(sourceFile: SourceFile): ts.NavigationBarItem[] {
|
||||
@@ -257,18 +256,18 @@ module ts.NavigationBar {
|
||||
return !text || text.trim() === "";
|
||||
}
|
||||
|
||||
function getNavigationBarItem(text: string, kind: string, kindModifiers: string, spans: TypeScript.TextSpan[], childItems: ts.NavigationBarItem[] = [], indent: number = 0): ts.NavigationBarItem {
|
||||
function getNavigationBarItem(text: string, kind: string, kindModifiers: string, spans: TextSpan[], childItems: NavigationBarItem[] = [], indent: number = 0): NavigationBarItem {
|
||||
if (isEmpty(text)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
text: text,
|
||||
kind: kind,
|
||||
kindModifiers: kindModifiers,
|
||||
spans: spans,
|
||||
childItems: childItems,
|
||||
indent: indent,
|
||||
text,
|
||||
kind,
|
||||
kindModifiers,
|
||||
spans,
|
||||
childItems,
|
||||
indent,
|
||||
bolded: false,
|
||||
grayed: false
|
||||
};
|
||||
@@ -424,8 +423,8 @@ module ts.NavigationBar {
|
||||
|
||||
function getNodeSpan(node: Node) {
|
||||
return node.kind === SyntaxKind.SourceFile
|
||||
? TypeScript.TextSpan.fromBounds(node.getFullStart(), node.getEnd())
|
||||
: TypeScript.TextSpan.fromBounds(node.getStart(), node.getEnd());
|
||||
? TextSpan.fromBounds(node.getFullStart(), node.getEnd())
|
||||
: TextSpan.fromBounds(node.getStart(), node.getEnd());
|
||||
}
|
||||
|
||||
function getTextOfNode(node: Node): string {
|
||||
|
||||
@@ -24,8 +24,8 @@ module ts {
|
||||
* @param autoCollapse Whether or not this region should be automatically collapsed when
|
||||
* the 'Collapse to Definitions' command is invoked.
|
||||
*/
|
||||
textSpan: TypeScript.TextSpan;
|
||||
hintSpan: TypeScript.TextSpan;
|
||||
textSpan: TextSpan;
|
||||
hintSpan: TextSpan;
|
||||
bannerText: string;
|
||||
autoCollapse: boolean;
|
||||
}
|
||||
@@ -38,8 +38,8 @@ module ts {
|
||||
function addOutliningSpan(hintSpanNode: Node, startElement: Node, endElement: Node, autoCollapse: boolean) {
|
||||
if (hintSpanNode && startElement && endElement) {
|
||||
var span: OutliningSpan = {
|
||||
textSpan: TypeScript.TextSpan.fromBounds(startElement.pos, endElement.end),
|
||||
hintSpan: TypeScript.TextSpan.fromBounds(hintSpanNode.getStart(), hintSpanNode.end),
|
||||
textSpan: TextSpan.fromBounds(startElement.pos, endElement.end),
|
||||
hintSpan: TextSpan.fromBounds(hintSpanNode.getStart(), hintSpanNode.end),
|
||||
bannerText: collapseText,
|
||||
autoCollapse: autoCollapse
|
||||
};
|
||||
@@ -86,7 +86,7 @@ module ts {
|
||||
else {
|
||||
// Block was a standalone block. In this case we want to only collapse
|
||||
// the span of the block, independent of any parent span.
|
||||
var span = TypeScript.TextSpan.fromBounds(n.getStart(), n.end);
|
||||
var span = TextSpan.fromBounds(n.getStart(), n.end);
|
||||
elements.push({
|
||||
textSpan: span,
|
||||
hintSpan: span,
|
||||
|
||||
@@ -5,7 +5,7 @@ module TypeScript {
|
||||
warning_TS_0_1: "warning TS{0}: {1}",
|
||||
Unrecognized_escape_sequence: "Unrecognized escape sequence.",
|
||||
Unexpected_character_0: "Unexpected character {0}.",
|
||||
Missing_close_quote_character: "Missing close quote character.",
|
||||
Unterminated_string_literal: "Unterminated string literal.",
|
||||
Identifier_expected: "Identifier expected.",
|
||||
_0_keyword_expected: "'{0}' keyword expected.",
|
||||
_0_expected: "'{0}' expected.",
|
||||
@@ -96,6 +96,9 @@ module TypeScript {
|
||||
Type_expected: "Type expected.",
|
||||
Template_literal_cannot_be_used_as_an_element_name: "Template literal cannot be used as an element name.",
|
||||
Computed_property_names_cannot_be_used_here: "Computed property names cannot be used here.",
|
||||
yield_expression_must_be_contained_within_a_generator_declaration: "'yield' expression must be contained within a generator declaration.",
|
||||
Unterminated_regular_expression_literal: "Unterminated regular expression literal.",
|
||||
Unterminated_template_literal: "Unterminated template literal.",
|
||||
Duplicate_identifier_0: "Duplicate identifier '{0}'.",
|
||||
The_name_0_does_not_exist_in_the_current_scope: "The name '{0}' does not exist in the current scope.",
|
||||
The_name_0_does_not_refer_to_a_value: "The name '{0}' does not refer to a value.",
|
||||
|
||||
@@ -6,7 +6,7 @@ module TypeScript {
|
||||
"warning TS{0}: {1}": { "code": 1, "category": DiagnosticCategory.NoPrefix },
|
||||
"Unrecognized escape sequence.": { "code": 1000, "category": DiagnosticCategory.Error },
|
||||
"Unexpected character {0}.": { "code": 1001, "category": DiagnosticCategory.Error },
|
||||
"Missing close quote character.": { "code": 1002, "category": DiagnosticCategory.Error },
|
||||
"Unterminated string literal.": { "code": 1002, "category": DiagnosticCategory.Error },
|
||||
"Identifier expected.": { "code": 1003, "category": DiagnosticCategory.Error },
|
||||
"'{0}' keyword expected.": { "code": 1004, "category": DiagnosticCategory.Error },
|
||||
"'{0}' expected.": { "code": 1005, "category": DiagnosticCategory.Error },
|
||||
@@ -98,6 +98,9 @@ module TypeScript {
|
||||
"Type expected.": { "code": 1110, "category": DiagnosticCategory.Error },
|
||||
"Template literal cannot be used as an element name.": { "code": 1111, "category": DiagnosticCategory.Error },
|
||||
"Computed property names cannot be used here.": { "code": 1112, "category": DiagnosticCategory.Error },
|
||||
"'yield' expression must be contained within a generator declaration.": { "code": 1113, "category": DiagnosticCategory.Error },
|
||||
"Unterminated regular expression literal.": { "code": 1114, "category": DiagnosticCategory.Error },
|
||||
"Unterminated template literal.": { "code": 1115, "category": DiagnosticCategory.Error },
|
||||
"Duplicate identifier '{0}'.": { "code": 2000, "category": DiagnosticCategory.Error },
|
||||
"The name '{0}' does not exist in the current scope.": { "code": 2001, "category": DiagnosticCategory.Error },
|
||||
"The name '{0}' does not refer to a value.": { "code": 2002, "category": DiagnosticCategory.Error },
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
"category": "Error",
|
||||
"code": 1001
|
||||
},
|
||||
"Missing close quote character.": {
|
||||
"Unterminated string literal.": {
|
||||
"category": "Error",
|
||||
"code": 1002
|
||||
},
|
||||
@@ -379,6 +379,18 @@
|
||||
"category": "Error",
|
||||
"code": 1112
|
||||
},
|
||||
"'yield' expression must be contained within a generator declaration.": {
|
||||
"category": "Error",
|
||||
"code": 1113
|
||||
},
|
||||
"Unterminated regular expression literal.": {
|
||||
"category": "Error",
|
||||
"code": 1114
|
||||
},
|
||||
"Unterminated template literal.": {
|
||||
"category": "Error",
|
||||
"code": 1115
|
||||
},
|
||||
"Duplicate identifier '{0}'.": {
|
||||
"category": "Error",
|
||||
"code": 2000
|
||||
|
||||
+250
-291
File diff suppressed because it is too large
Load Diff
+10
-28
@@ -15,8 +15,6 @@
|
||||
|
||||
/// <reference path='services.ts' />
|
||||
|
||||
/// <reference path='compiler\pathUtils.ts' />
|
||||
|
||||
var debugObjectHost = (<any>this);
|
||||
|
||||
module ts {
|
||||
@@ -135,12 +133,6 @@ module ts {
|
||||
*/
|
||||
getOccurrencesAtPosition(fileName: string, position: number): string;
|
||||
|
||||
/**
|
||||
* Returns a JSON-encoded value of the type:
|
||||
* { fileName: string; textSpan: { start: number; length: number}; isWriteAccess: boolean }[]
|
||||
*/
|
||||
getImplementorsAtPosition(fileName: string, position: number): string;
|
||||
|
||||
/**
|
||||
* Returns a JSON-encoded value of the type:
|
||||
* { name: string; kind: string; kindModifiers: string; containerName: string; containerKind: string; matchKind: string; fileName: string; textSpan: { start: number; length: number}; } [] = [];
|
||||
@@ -176,7 +168,7 @@ module ts {
|
||||
}
|
||||
|
||||
export interface CoreServicesShim extends Shim {
|
||||
getPreProcessedFileInfo(fileName: string, sourceText: TypeScript.IScriptSnapshot): string;
|
||||
getPreProcessedFileInfo(fileName: string, sourceText: IScriptSnapshot): string;
|
||||
getDefaultCompilationSettings(): string;
|
||||
}
|
||||
|
||||
@@ -309,7 +301,7 @@ module ts {
|
||||
logger.log("*INTERNAL ERROR* - Exception in typescript services: " + err.message);
|
||||
}
|
||||
|
||||
class ScriptSnapshotShimAdapter implements TypeScript.IScriptSnapshot {
|
||||
class ScriptSnapshotShimAdapter implements IScriptSnapshot {
|
||||
private lineStartPositions: number[] = null;
|
||||
|
||||
constructor(private scriptSnapshotShim: ScriptSnapshotShim) {
|
||||
@@ -331,7 +323,7 @@ module ts {
|
||||
return this.lineStartPositions;
|
||||
}
|
||||
|
||||
public getChangeRange(oldSnapshot: TypeScript.IScriptSnapshot): TypeScript.TextChangeRange {
|
||||
public getChangeRange(oldSnapshot: IScriptSnapshot): TextChangeRange {
|
||||
var oldSnapshotShim = <ScriptSnapshotShimAdapter>oldSnapshot;
|
||||
var encoded = this.scriptSnapshotShim.getChangeRange(oldSnapshotShim.scriptSnapshotShim);
|
||||
if (encoded == null) {
|
||||
@@ -339,8 +331,8 @@ module ts {
|
||||
}
|
||||
|
||||
var decoded: { span: { start: number; length: number; }; newLength: number; } = JSON.parse(encoded);
|
||||
return new TypeScript.TextChangeRange(
|
||||
new TypeScript.TextSpan(decoded.span.start, decoded.span.length), decoded.newLength);
|
||||
return new TextChangeRange(
|
||||
new TextSpan(decoded.span.start, decoded.span.length), decoded.newLength);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,7 +360,7 @@ module ts {
|
||||
return JSON.parse(encoded);
|
||||
}
|
||||
|
||||
public getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot {
|
||||
public getScriptSnapshot(fileName: string): IScriptSnapshot {
|
||||
return new ScriptSnapshotShimAdapter(this.shimHost.getScriptSnapshot(fileName));
|
||||
}
|
||||
|
||||
@@ -521,7 +513,7 @@ module ts {
|
||||
return this.forwardJSONCall(
|
||||
"getSyntacticClassifications('" + fileName + "', " + start + ", " + length + ")",
|
||||
() => {
|
||||
var classifications = this.languageService.getSyntacticClassifications(fileName, new TypeScript.TextSpan(start, length));
|
||||
var classifications = this.languageService.getSyntacticClassifications(fileName, new TextSpan(start, length));
|
||||
return classifications;
|
||||
});
|
||||
}
|
||||
@@ -530,7 +522,7 @@ module ts {
|
||||
return this.forwardJSONCall(
|
||||
"getSemanticClassifications('" + fileName + "', " + start + ", " + length + ")",
|
||||
() => {
|
||||
var classifications = this.languageService.getSemanticClassifications(fileName, new TypeScript.TextSpan(start, length));
|
||||
var classifications = this.languageService.getSemanticClassifications(fileName, new TextSpan(start, length));
|
||||
return classifications;
|
||||
});
|
||||
}
|
||||
@@ -698,16 +690,6 @@ module ts {
|
||||
});
|
||||
}
|
||||
|
||||
/// GET IMPLEMENTORS
|
||||
public getImplementorsAtPosition(fileName: string, position: number): string {
|
||||
return this.forwardJSONCall(
|
||||
"getImplementorsAtPosition('" + fileName + "', " + position + ")",
|
||||
() => {
|
||||
return this.languageService.getImplementorsAtPosition(fileName, position);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/// COMPLETION LISTS
|
||||
|
||||
/**
|
||||
@@ -845,7 +827,7 @@ module ts {
|
||||
return forwardJSONCall(this.logger, actionDescription, action);
|
||||
}
|
||||
|
||||
public getPreProcessedFileInfo(fileName: string, sourceTextSnapshot: TypeScript.IScriptSnapshot): string {
|
||||
public getPreProcessedFileInfo(fileName: string, sourceTextSnapshot: IScriptSnapshot): string {
|
||||
return this.forwardJSONCall(
|
||||
"getPreProcessedFileInfo('" + fileName + "')",
|
||||
() => {
|
||||
@@ -938,7 +920,7 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
throw TypeScript.Errors.invalidOperation();
|
||||
throw new Error("Invalid operation");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +221,7 @@ module ts.SignatureHelp {
|
||||
var list = getChildListThatStartsWithOpenerToken(parent, node, sourceFile);
|
||||
Debug.assert(list !== undefined);
|
||||
return {
|
||||
list: list,
|
||||
list,
|
||||
listItemIndex: 0
|
||||
};
|
||||
}
|
||||
@@ -303,40 +303,40 @@ module ts.SignatureHelp {
|
||||
var callTargetDisplayParts = callTargetSymbol && symbolToDisplayParts(typeInfoResolver, callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined);
|
||||
var items: SignatureHelpItem[] = map(candidates, candidateSignature => {
|
||||
var signatureHelpParameters: SignatureHelpParameter[];
|
||||
var prefixParts: SymbolDisplayPart[] = [];
|
||||
var suffixParts: SymbolDisplayPart[] = [];
|
||||
var prefixDisplayParts: SymbolDisplayPart[] = [];
|
||||
var suffixDisplayParts: SymbolDisplayPart[] = [];
|
||||
|
||||
if (callTargetDisplayParts) {
|
||||
prefixParts.push.apply(prefixParts, callTargetDisplayParts);
|
||||
prefixDisplayParts.push.apply(prefixDisplayParts, callTargetDisplayParts);
|
||||
}
|
||||
|
||||
if (isTypeParameterHelp) {
|
||||
prefixParts.push(punctuationPart(SyntaxKind.LessThanToken));
|
||||
prefixDisplayParts.push(punctuationPart(SyntaxKind.LessThanToken));
|
||||
var typeParameters = candidateSignature.typeParameters;
|
||||
signatureHelpParameters = typeParameters && typeParameters.length > 0 ? map(typeParameters, createSignatureHelpParameterForTypeParameter) : emptyArray;
|
||||
suffixParts.push(punctuationPart(SyntaxKind.GreaterThanToken));
|
||||
suffixDisplayParts.push(punctuationPart(SyntaxKind.GreaterThanToken));
|
||||
var parameterParts = mapToDisplayParts(writer =>
|
||||
typeInfoResolver.getSymbolDisplayBuilder().buildDisplayForParametersAndDelimiters(candidateSignature.parameters, writer, argumentListOrTypeArgumentList));
|
||||
suffixParts.push.apply(suffixParts, parameterParts);
|
||||
suffixDisplayParts.push.apply(suffixDisplayParts, parameterParts);
|
||||
}
|
||||
else {
|
||||
var typeParameterParts = mapToDisplayParts(writer =>
|
||||
typeInfoResolver.getSymbolDisplayBuilder().buildDisplayForTypeParametersAndDelimiters(candidateSignature.typeParameters, writer, argumentListOrTypeArgumentList));
|
||||
prefixParts.push.apply(prefixParts, typeParameterParts);
|
||||
prefixParts.push(punctuationPart(SyntaxKind.OpenParenToken));
|
||||
prefixDisplayParts.push.apply(prefixDisplayParts, typeParameterParts);
|
||||
prefixDisplayParts.push(punctuationPart(SyntaxKind.OpenParenToken));
|
||||
var parameters = candidateSignature.parameters;
|
||||
signatureHelpParameters = parameters.length > 0 ? map(parameters, createSignatureHelpParameterForParameter) : emptyArray;
|
||||
suffixParts.push(punctuationPart(SyntaxKind.CloseParenToken));
|
||||
suffixDisplayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
|
||||
}
|
||||
|
||||
var returnTypeParts = mapToDisplayParts(writer =>
|
||||
typeInfoResolver.getSymbolDisplayBuilder().buildReturnTypeDisplay(candidateSignature, writer, argumentListOrTypeArgumentList));
|
||||
suffixParts.push.apply(suffixParts, returnTypeParts);
|
||||
suffixDisplayParts.push.apply(suffixDisplayParts, returnTypeParts);
|
||||
|
||||
return {
|
||||
isVariadic: candidateSignature.hasRestParameter,
|
||||
prefixDisplayParts: prefixParts,
|
||||
suffixDisplayParts: suffixParts,
|
||||
prefixDisplayParts,
|
||||
suffixDisplayParts,
|
||||
separatorDisplayParts: [punctuationPart(SyntaxKind.CommaToken), spacePart()],
|
||||
parameters: signatureHelpParameters,
|
||||
documentation: candidateSignature.getDocumentationComment()
|
||||
@@ -353,7 +353,7 @@ module ts.SignatureHelp {
|
||||
// but not including parentheses)
|
||||
var applicableSpanStart = argumentListOrTypeArgumentList.getFullStart();
|
||||
var applicableSpanEnd = skipTrivia(sourceFile.text, argumentListOrTypeArgumentList.end, /*stopAfterLineBreak*/ false);
|
||||
var applicableSpan = new TypeScript.TextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart);
|
||||
var applicableSpan = new TextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart);
|
||||
|
||||
// The listItemIndex we got back includes commas. Our goal is to return the index of the proper
|
||||
// item (not including commas). Here are some examples:
|
||||
@@ -378,11 +378,11 @@ module ts.SignatureHelp {
|
||||
}
|
||||
|
||||
return {
|
||||
items: items,
|
||||
applicableSpan: applicableSpan,
|
||||
selectedItemIndex: selectedItemIndex,
|
||||
argumentIndex: argumentIndex,
|
||||
argumentCount: argumentCount
|
||||
items,
|
||||
applicableSpan,
|
||||
selectedItemIndex,
|
||||
argumentIndex,
|
||||
argumentCount
|
||||
};
|
||||
|
||||
function createSignatureHelpParameterForParameter(parameter: Symbol): SignatureHelpParameter {
|
||||
@@ -394,8 +394,8 @@ module ts.SignatureHelp {
|
||||
return {
|
||||
name: parameter.name,
|
||||
documentation: parameter.getDocumentationComment(),
|
||||
displayParts: displayParts,
|
||||
isOptional: isOptional
|
||||
displayParts,
|
||||
isOptional
|
||||
};
|
||||
}
|
||||
|
||||
@@ -406,7 +406,7 @@ module ts.SignatureHelp {
|
||||
return {
|
||||
name: typeParameter.symbol.name,
|
||||
documentation: emptyArray,
|
||||
displayParts: displayParts,
|
||||
displayParts,
|
||||
isOptional: false
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
///<reference path='..\services.ts' />
|
||||
///<reference path='services.ts' />
|
||||
|
||||
module ts.formatting {
|
||||
export module SmartIndenter {
|
||||
export function getIndentation(position: number, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number {
|
||||
export function getIndentation(position: number, sourceFile: SourceFile, options: EditorOptions): number {
|
||||
if (position > sourceFile.text.length) {
|
||||
return 0; // past EOF
|
||||
}
|
||||
@@ -13,8 +13,8 @@ module ts.formatting {
|
||||
}
|
||||
|
||||
// no indentation in string \regex literals
|
||||
if ((precedingToken.kind === SyntaxKind.StringLiteral || precedingToken.kind === SyntaxKind.RegularExpressionLiteral) &&
|
||||
precedingToken.getStart(sourceFile) <= position &&
|
||||
if ((precedingToken.kind === SyntaxKind.StringLiteral || precedingToken.kind === SyntaxKind.RegularExpressionLiteral) &&
|
||||
precedingToken.getStart(sourceFile) <= position &&
|
||||
precedingToken.end > position) {
|
||||
return 0;
|
||||
}
|
||||
@@ -37,14 +37,14 @@ module ts.formatting {
|
||||
var indentationDelta: number;
|
||||
|
||||
while (current) {
|
||||
if (positionBelongsToNode(current, position, sourceFile) && nodeContentIsIndented(current, previous)) {
|
||||
if (positionBelongsToNode(current, position, sourceFile) && shouldIndentChildNode(current.kind, previous ? previous.kind : SyntaxKind.Unknown)) {
|
||||
currentStart = getStartLineAndCharacterForNode(current, sourceFile);
|
||||
|
||||
if (nextTokenIsCurlyBraceOnSameLineAsCursor(precedingToken, current, lineAtPosition, sourceFile)) {
|
||||
indentationDelta = 0;
|
||||
}
|
||||
else {
|
||||
indentationDelta = lineAtPosition !== currentStart.line ? options.indentSpaces : 0;
|
||||
indentationDelta = lineAtPosition !== currentStart.line ? options.IndentSize : 0;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -59,12 +59,27 @@ module ts.formatting {
|
||||
previous = current;
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
|
||||
if (!current) {
|
||||
// no parent was found - return 0 to be indented on the level of SourceFile
|
||||
return 0;
|
||||
}
|
||||
|
||||
return getIndentationForNodeWorker(current, currentStart, /*ignoreActualIndentationRange*/ undefined, indentationDelta, sourceFile, options);
|
||||
}
|
||||
|
||||
export function getIndentationForNode(n: Node, ignoreActualIndentationRange: TextRange, sourceFile: SourceFile, options: FormatCodeOptions): number {
|
||||
var start = sourceFile.getLineAndCharacterFromPosition(n.getStart(sourceFile));
|
||||
return getIndentationForNodeWorker(n, start, ignoreActualIndentationRange, /*indentationDelta*/ 0, sourceFile, options);
|
||||
}
|
||||
|
||||
function getIndentationForNodeWorker(
|
||||
current: Node,
|
||||
currentStart: LineAndCharacter,
|
||||
ignoreActualIndentationRange: TextRange,
|
||||
indentationDelta: number,
|
||||
sourceFile: SourceFile,
|
||||
options: EditorOptions): number {
|
||||
|
||||
var parent: Node = current.parent;
|
||||
var parentStart: LineAndCharacter;
|
||||
@@ -72,26 +87,35 @@ module ts.formatting {
|
||||
// walk upwards and collect indentations for pairs of parent-child nodes
|
||||
// indentation is not added if parent and child nodes start on the same line or if parent is IfStatement and child starts on the same line with 'else clause'
|
||||
while (parent) {
|
||||
// check if current node is a list item - if yes, take indentation from it
|
||||
var actualIndentation = getActualIndentationForListItem(current, sourceFile, options);
|
||||
if (actualIndentation !== -1) {
|
||||
return actualIndentation + indentationDelta;
|
||||
var useActualIndentation = true;
|
||||
if (ignoreActualIndentationRange) {
|
||||
var start = current.getStart(sourceFile);
|
||||
useActualIndentation = start < ignoreActualIndentationRange.pos || start > ignoreActualIndentationRange.end;
|
||||
}
|
||||
|
||||
parentStart = sourceFile.getLineAndCharacterFromPosition(parent.getStart(sourceFile));
|
||||
var parentAndChildShareLine =
|
||||
parentStart.line === currentStart.line ||
|
||||
if (useActualIndentation) {
|
||||
// check if current node is a list item - if yes, take indentation from it
|
||||
var actualIndentation = getActualIndentationForListItem(current, sourceFile, options);
|
||||
if (actualIndentation !== -1) {
|
||||
return actualIndentation + indentationDelta;
|
||||
}
|
||||
}
|
||||
parentStart = getParentStart(parent, current, sourceFile);
|
||||
var parentAndChildShareLine =
|
||||
parentStart.line === currentStart.line ||
|
||||
childStartsOnTheSameLineWithElseInIfStatement(parent, current, currentStart.line, sourceFile);
|
||||
|
||||
// try to fetch actual indentation for current node from source text
|
||||
var actualIndentation = getActualIndentationForNode(current, parent, currentStart, parentAndChildShareLine, sourceFile, options);
|
||||
if (actualIndentation !== -1) {
|
||||
return actualIndentation + indentationDelta;
|
||||
if (useActualIndentation) {
|
||||
// try to fetch actual indentation for current node from source text
|
||||
var actualIndentation = getActualIndentationForNode(current, parent, currentStart, parentAndChildShareLine, sourceFile, options);
|
||||
if (actualIndentation !== -1) {
|
||||
return actualIndentation + indentationDelta;
|
||||
}
|
||||
}
|
||||
|
||||
// increase indentation if parent node wants its content to be indented and parent and child nodes don't start on the same line
|
||||
if (nodeContentIsIndented(parent, current) && !parentAndChildShareLine) {
|
||||
indentationDelta += options.indentSpaces;
|
||||
if (shouldIndentChildNode(parent.kind, current.kind) && !parentAndChildShareLine) {
|
||||
indentationDelta += options.IndentSize;
|
||||
}
|
||||
|
||||
current = parent;
|
||||
@@ -102,10 +126,20 @@ module ts.formatting {
|
||||
return indentationDelta;
|
||||
}
|
||||
|
||||
|
||||
function getParentStart(parent: Node, child: Node, sourceFile: SourceFile): LineAndCharacter {
|
||||
var containingList = getContainingList(child, sourceFile);
|
||||
if (containingList) {
|
||||
return sourceFile.getLineAndCharacterFromPosition(containingList.pos);
|
||||
}
|
||||
|
||||
return sourceFile.getLineAndCharacterFromPosition(parent.getStart(sourceFile));
|
||||
}
|
||||
|
||||
/*
|
||||
* Function returns -1 if indentation cannot be determined
|
||||
*/
|
||||
function getActualIndentationForListItemBeforeComma(commaToken: Node, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number {
|
||||
*/
|
||||
function getActualIndentationForListItemBeforeComma(commaToken: Node, sourceFile: SourceFile, options: EditorOptions): number {
|
||||
// previous token is comma that separates items in list - find the previous item and try to derive indentation from it
|
||||
var commaItemInfo = findListItemInfo(commaToken);
|
||||
Debug.assert(commaItemInfo && commaItemInfo.listItemIndex > 0);
|
||||
@@ -116,20 +150,20 @@ module ts.formatting {
|
||||
/*
|
||||
* Function returns -1 if actual indentation for node should not be used (i.e because node is nested expression)
|
||||
*/
|
||||
function getActualIndentationForNode(current: Node,
|
||||
parent: Node,
|
||||
currentLineAndChar: LineAndCharacter,
|
||||
parentAndChildShareLine: boolean,
|
||||
sourceFile: SourceFile,
|
||||
options: TypeScript.FormattingOptions): number {
|
||||
function getActualIndentationForNode(current: Node,
|
||||
parent: Node,
|
||||
currentLineAndChar: LineAndCharacter,
|
||||
parentAndChildShareLine: boolean,
|
||||
sourceFile: SourceFile,
|
||||
options: EditorOptions): number {
|
||||
|
||||
// actual indentation is used for statements\declarations if one of cases below is true:
|
||||
// - parent is SourceFile - by default immediate children of SourceFile are not indented except when user indents them manually
|
||||
// - parent and child are not on the same line
|
||||
var useActualIndentation =
|
||||
var useActualIndentation =
|
||||
(isDeclaration(current) || isStatement(current)) &&
|
||||
(parent.kind === SyntaxKind.SourceFile || !parentAndChildShareLine);
|
||||
|
||||
|
||||
if (!useActualIndentation) {
|
||||
return -1;
|
||||
}
|
||||
@@ -142,7 +176,7 @@ module ts.formatting {
|
||||
if (!nextToken) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (nextToken.kind === SyntaxKind.OpenBraceToken) {
|
||||
// open braces are always indented at the parent level
|
||||
return true;
|
||||
@@ -172,52 +206,65 @@ module ts.formatting {
|
||||
return candidate.end > position || !isCompletedNode(candidate, sourceFile);
|
||||
}
|
||||
|
||||
function childStartsOnTheSameLineWithElseInIfStatement(parent: Node, child: Node, childStartLine: number, sourceFile: SourceFile): boolean {
|
||||
export function childStartsOnTheSameLineWithElseInIfStatement(parent: Node, child: TextRangeWithKind, childStartLine: number, sourceFile: SourceFile): boolean {
|
||||
if (parent.kind === SyntaxKind.IfStatement && (<IfStatement>parent).elseStatement === child) {
|
||||
var elseKeyword = findChildOfKind(parent, SyntaxKind.ElseKeyword, sourceFile);
|
||||
Debug.assert(elseKeyword !== undefined);
|
||||
|
||||
var elseKeywordStartLine = getStartLineAndCharacterForNode(elseKeyword, sourceFile).line;
|
||||
var elseKeywordStartLine = getStartLineAndCharacterForNode(elseKeyword, sourceFile).line;
|
||||
return elseKeywordStartLine === childStartLine;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number {
|
||||
function getContainingList(node: Node, sourceFile: SourceFile): NodeArray<Node> {
|
||||
if (node.parent) {
|
||||
switch (node.parent.kind) {
|
||||
case SyntaxKind.TypeReference:
|
||||
if ((<TypeReferenceNode>node.parent).typeArguments) {
|
||||
return getActualIndentationFromList((<TypeReferenceNode>node.parent).typeArguments);
|
||||
if ((<TypeReferenceNode>node.parent).typeArguments &&
|
||||
rangeContainsStartEnd((<TypeReferenceNode>node.parent).typeArguments, node.getStart(sourceFile), node.getEnd())) {
|
||||
return (<TypeReferenceNode>node.parent).typeArguments;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.ObjectLiteral:
|
||||
return getActualIndentationFromList((<ObjectLiteral>node.parent).properties);
|
||||
case SyntaxKind.TypeLiteral:
|
||||
return getActualIndentationFromList((<TypeLiteralNode>node.parent).members);
|
||||
return (<ObjectLiteral>node.parent).properties;
|
||||
case SyntaxKind.ArrayLiteral:
|
||||
return getActualIndentationFromList((<ArrayLiteral>node.parent).elements);
|
||||
return (<ArrayLiteral>node.parent).elements;
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.CallSignature:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
if ((<SignatureDeclaration>node.parent).typeParameters && node.end < (<SignatureDeclaration>node.parent).typeParameters.end) {
|
||||
return getActualIndentationFromList((<SignatureDeclaration>node.parent).typeParameters);
|
||||
var start = node.getStart(sourceFile);
|
||||
if ((<SignatureDeclaration>node.parent).typeParameters &&
|
||||
rangeContainsStartEnd((<SignatureDeclaration>node.parent).typeParameters, start, node.getEnd())) {
|
||||
return (<SignatureDeclaration>node.parent).typeParameters;
|
||||
}
|
||||
|
||||
return getActualIndentationFromList((<SignatureDeclaration>node.parent).parameters);
|
||||
if (rangeContainsStartEnd((<SignatureDeclaration>node.parent).parameters, start, node.getEnd())) {
|
||||
return (<SignatureDeclaration>node.parent).parameters;
|
||||
}
|
||||
break;
|
||||
case SyntaxKind.NewExpression:
|
||||
case SyntaxKind.CallExpression:
|
||||
if ((<CallExpression>node.parent).typeArguments && node.end < (<CallExpression>node.parent).typeArguments.end) {
|
||||
return getActualIndentationFromList((<CallExpression>node.parent).typeArguments);
|
||||
var start = node.getStart(sourceFile);
|
||||
if ((<CallExpression>node.parent).typeArguments &&
|
||||
rangeContainsStartEnd((<CallExpression>node.parent).typeArguments, start, node.getEnd())) {
|
||||
return (<CallExpression>node.parent).typeArguments;
|
||||
}
|
||||
|
||||
return getActualIndentationFromList((<CallExpression>node.parent).arguments);
|
||||
if (rangeContainsStartEnd((<CallExpression>node.parent).arguments, start, node.getEnd())) {
|
||||
return (<CallExpression>node.parent).arguments;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return -1;
|
||||
function getActualIndentationForListItem(node: Node, sourceFile: SourceFile, options: EditorOptions): number {
|
||||
var containingList = getContainingList(node, sourceFile);
|
||||
return containingList ? getActualIndentationFromList(containingList) : -1;
|
||||
|
||||
function getActualIndentationFromList(list: Node[]): number {
|
||||
var index = indexOf(list, node);
|
||||
@@ -226,13 +273,13 @@ module ts.formatting {
|
||||
}
|
||||
|
||||
|
||||
function deriveActualIndentationFromList(list: Node[], index: number, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number {
|
||||
function deriveActualIndentationFromList(list: Node[], index: number, sourceFile: SourceFile, options: EditorOptions): number {
|
||||
Debug.assert(index >= 0 && index < list.length);
|
||||
var node = list[index];
|
||||
|
||||
// walk toward the start of the list starting from current node and check if the line is the same for all items.
|
||||
// if end line for item [i - 1] differs from the start line for item [i] - find column of the first non-whitespace character on the line of item [i]
|
||||
var lineAndCharacter = getStartLineAndCharacterForNode(node, sourceFile);
|
||||
var lineAndCharacter = getStartLineAndCharacterForNode(node, sourceFile);
|
||||
for (var i = index - 1; i >= 0; --i) {
|
||||
if (list[i].kind === SyntaxKind.CommaToken) {
|
||||
continue;
|
||||
@@ -248,53 +295,34 @@ module ts.formatting {
|
||||
return -1;
|
||||
}
|
||||
|
||||
function findColumnForFirstNonWhitespaceCharacterInLine(lineAndCharacter: LineAndCharacter, sourceFile: SourceFile, options: TypeScript.FormattingOptions): number {
|
||||
function findColumnForFirstNonWhitespaceCharacterInLine(lineAndCharacter: LineAndCharacter, sourceFile: SourceFile, options: EditorOptions): number {
|
||||
var lineStart = sourceFile.getPositionFromLineAndCharacter(lineAndCharacter.line, 1);
|
||||
return findFirstNonWhitespaceColumn(lineStart, lineStart + lineAndCharacter.character, sourceFile, options);
|
||||
}
|
||||
|
||||
export function findFirstNonWhitespaceColumn(startPos: number, endPos: number, sourceFile: SourceFile, options: EditorOptions): number {
|
||||
var column = 0;
|
||||
for (var i = 0; i < lineAndCharacter.character; ++i) {
|
||||
var charCode = sourceFile.text.charCodeAt(lineStart + i);
|
||||
if (!isWhiteSpace(charCode)) {
|
||||
for (var pos = startPos; pos < endPos; ++pos) {
|
||||
var ch = sourceFile.text.charCodeAt(pos);
|
||||
if (!isWhiteSpace(ch)) {
|
||||
return column;
|
||||
}
|
||||
|
||||
if (charCode === CharacterCodes.tab) {
|
||||
column += options.spacesPerTab;
|
||||
if (ch === CharacterCodes.tab) {
|
||||
column += options.TabSize + (column % options.TabSize);
|
||||
}
|
||||
else {
|
||||
column++;
|
||||
}
|
||||
}
|
||||
|
||||
return column;
|
||||
}
|
||||
|
||||
function nodeContentIsIndented(parent: Node, child: Node): boolean {
|
||||
switch (parent.kind) {
|
||||
function nodeContentIsAlwaysIndented(kind: SyntaxKind): boolean {
|
||||
switch (kind) {
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
return true;
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
// ModuleBlock should take care of indentation
|
||||
return false;
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.Constructor:
|
||||
// FunctionBlock should take care of indentation
|
||||
return false;
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.ForStatement:
|
||||
return child && child.kind !== SyntaxKind.Block;
|
||||
case SyntaxKind.IfStatement:
|
||||
return child && child.kind !== SyntaxKind.Block;
|
||||
case SyntaxKind.TryStatement:
|
||||
// TryBlock\CatchBlock\FinallyBlock should take care of indentation
|
||||
return false;
|
||||
case SyntaxKind.ArrayLiteral:
|
||||
case SyntaxKind.Block:
|
||||
case SyntaxKind.FunctionBlock:
|
||||
@@ -312,7 +340,32 @@ module ts.formatting {
|
||||
case SyntaxKind.NewExpression:
|
||||
case SyntaxKind.VariableStatement:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
case SyntaxKind.ExportAssignment:
|
||||
case SyntaxKind.ReturnStatement:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function shouldIndentChildNode(parent: SyntaxKind, child: SyntaxKind): boolean {
|
||||
if (nodeContentIsAlwaysIndented(parent)) {
|
||||
return true;
|
||||
}
|
||||
switch (parent) {
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.ForStatement:
|
||||
case SyntaxKind.IfStatement:
|
||||
return child !== SyntaxKind.Block;
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.Method:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.Constructor:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
return child !== SyntaxKind.FunctionBlock;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -368,7 +421,7 @@ module ts.formatting {
|
||||
if ((<IfStatement>n).elseStatement) {
|
||||
return isCompletedNode((<IfStatement>n).elseStatement, sourceFile);
|
||||
}
|
||||
return isCompletedNode((<IfStatement>n).thenStatement, sourceFile);
|
||||
return isCompletedNode((<IfStatement>n).thenStatement, sourceFile);
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
return isCompletedNode((<ExpressionStatement>n).expression, sourceFile);
|
||||
case SyntaxKind.ArrayLiteral:
|
||||
@@ -384,10 +437,10 @@ module ts.formatting {
|
||||
case SyntaxKind.DoStatement:
|
||||
// rough approximation: if DoStatement has While keyword - then if node is completed is checking the presence of ')';
|
||||
var hasWhileKeyword = findChildOfKind(n, SyntaxKind.WhileKeyword, sourceFile);
|
||||
if(hasWhileKeyword) {
|
||||
if (hasWhileKeyword) {
|
||||
return nodeEndsWith(n, SyntaxKind.CloseParenToken, sourceFile);
|
||||
}
|
||||
return isCompletedNode((<DoStatement>n).statement, sourceFile);
|
||||
return isCompletedNode((<DoStatement>n).statement, sourceFile);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
@@ -599,30 +599,31 @@ var TypeScript;
|
||||
SyntaxKind[SyntaxKind["OmittedExpression"] = 187] = "OmittedExpression";
|
||||
SyntaxKind[SyntaxKind["TemplateExpression"] = 188] = "TemplateExpression";
|
||||
SyntaxKind[SyntaxKind["TemplateAccessExpression"] = 189] = "TemplateAccessExpression";
|
||||
SyntaxKind[SyntaxKind["VariableDeclaration"] = 190] = "VariableDeclaration";
|
||||
SyntaxKind[SyntaxKind["VariableDeclarator"] = 191] = "VariableDeclarator";
|
||||
SyntaxKind[SyntaxKind["ArgumentList"] = 192] = "ArgumentList";
|
||||
SyntaxKind[SyntaxKind["ParameterList"] = 193] = "ParameterList";
|
||||
SyntaxKind[SyntaxKind["TypeArgumentList"] = 194] = "TypeArgumentList";
|
||||
SyntaxKind[SyntaxKind["TypeParameterList"] = 195] = "TypeParameterList";
|
||||
SyntaxKind[SyntaxKind["HeritageClause"] = 196] = "HeritageClause";
|
||||
SyntaxKind[SyntaxKind["EqualsValueClause"] = 197] = "EqualsValueClause";
|
||||
SyntaxKind[SyntaxKind["CaseSwitchClause"] = 198] = "CaseSwitchClause";
|
||||
SyntaxKind[SyntaxKind["DefaultSwitchClause"] = 199] = "DefaultSwitchClause";
|
||||
SyntaxKind[SyntaxKind["ElseClause"] = 200] = "ElseClause";
|
||||
SyntaxKind[SyntaxKind["CatchClause"] = 201] = "CatchClause";
|
||||
SyntaxKind[SyntaxKind["FinallyClause"] = 202] = "FinallyClause";
|
||||
SyntaxKind[SyntaxKind["TemplateClause"] = 203] = "TemplateClause";
|
||||
SyntaxKind[SyntaxKind["TypeParameter"] = 204] = "TypeParameter";
|
||||
SyntaxKind[SyntaxKind["Constraint"] = 205] = "Constraint";
|
||||
SyntaxKind[SyntaxKind["SimplePropertyAssignment"] = 206] = "SimplePropertyAssignment";
|
||||
SyntaxKind[SyntaxKind["FunctionPropertyAssignment"] = 207] = "FunctionPropertyAssignment";
|
||||
SyntaxKind[SyntaxKind["Parameter"] = 208] = "Parameter";
|
||||
SyntaxKind[SyntaxKind["EnumElement"] = 209] = "EnumElement";
|
||||
SyntaxKind[SyntaxKind["TypeAnnotation"] = 210] = "TypeAnnotation";
|
||||
SyntaxKind[SyntaxKind["ComputedPropertyName"] = 211] = "ComputedPropertyName";
|
||||
SyntaxKind[SyntaxKind["ExternalModuleReference"] = 212] = "ExternalModuleReference";
|
||||
SyntaxKind[SyntaxKind["ModuleNameModuleReference"] = 213] = "ModuleNameModuleReference";
|
||||
SyntaxKind[SyntaxKind["YieldExpression"] = 190] = "YieldExpression";
|
||||
SyntaxKind[SyntaxKind["VariableDeclaration"] = 191] = "VariableDeclaration";
|
||||
SyntaxKind[SyntaxKind["VariableDeclarator"] = 192] = "VariableDeclarator";
|
||||
SyntaxKind[SyntaxKind["ArgumentList"] = 193] = "ArgumentList";
|
||||
SyntaxKind[SyntaxKind["ParameterList"] = 194] = "ParameterList";
|
||||
SyntaxKind[SyntaxKind["TypeArgumentList"] = 195] = "TypeArgumentList";
|
||||
SyntaxKind[SyntaxKind["TypeParameterList"] = 196] = "TypeParameterList";
|
||||
SyntaxKind[SyntaxKind["HeritageClause"] = 197] = "HeritageClause";
|
||||
SyntaxKind[SyntaxKind["EqualsValueClause"] = 198] = "EqualsValueClause";
|
||||
SyntaxKind[SyntaxKind["CaseSwitchClause"] = 199] = "CaseSwitchClause";
|
||||
SyntaxKind[SyntaxKind["DefaultSwitchClause"] = 200] = "DefaultSwitchClause";
|
||||
SyntaxKind[SyntaxKind["ElseClause"] = 201] = "ElseClause";
|
||||
SyntaxKind[SyntaxKind["CatchClause"] = 202] = "CatchClause";
|
||||
SyntaxKind[SyntaxKind["FinallyClause"] = 203] = "FinallyClause";
|
||||
SyntaxKind[SyntaxKind["TemplateClause"] = 204] = "TemplateClause";
|
||||
SyntaxKind[SyntaxKind["TypeParameter"] = 205] = "TypeParameter";
|
||||
SyntaxKind[SyntaxKind["Constraint"] = 206] = "Constraint";
|
||||
SyntaxKind[SyntaxKind["SimplePropertyAssignment"] = 207] = "SimplePropertyAssignment";
|
||||
SyntaxKind[SyntaxKind["FunctionPropertyAssignment"] = 208] = "FunctionPropertyAssignment";
|
||||
SyntaxKind[SyntaxKind["Parameter"] = 209] = "Parameter";
|
||||
SyntaxKind[SyntaxKind["EnumElement"] = 210] = "EnumElement";
|
||||
SyntaxKind[SyntaxKind["TypeAnnotation"] = 211] = "TypeAnnotation";
|
||||
SyntaxKind[SyntaxKind["ComputedPropertyName"] = 212] = "ComputedPropertyName";
|
||||
SyntaxKind[SyntaxKind["ExternalModuleReference"] = 213] = "ExternalModuleReference";
|
||||
SyntaxKind[SyntaxKind["ModuleNameModuleReference"] = 214] = "ModuleNameModuleReference";
|
||||
SyntaxKind[SyntaxKind["FirstStandardKeyword"] = SyntaxKind.BreakKeyword] = "FirstStandardKeyword";
|
||||
SyntaxKind[SyntaxKind["LastStandardKeyword"] = SyntaxKind.WithKeyword] = "LastStandardKeyword";
|
||||
SyntaxKind[SyntaxKind["FirstFutureReservedKeyword"] = SyntaxKind.ClassKeyword] = "FirstFutureReservedKeyword";
|
||||
@@ -910,9 +911,9 @@ var definitions = [
|
||||
baseType: 'ISyntaxNode',
|
||||
interfaces: ['IModuleReferenceSyntax'],
|
||||
children: [
|
||||
{ name: 'requireKeyword', isToken: true, tokenKinds: ['RequireKeyword'], excludeFromAST: true },
|
||||
{ name: 'requireKeyword', isToken: true, excludeFromAST: true },
|
||||
{ name: 'openParenToken', isToken: true, excludeFromAST: true },
|
||||
{ name: 'stringLiteral', isToken: true, tokenKinds: ['StringLiteral'] },
|
||||
{ name: 'stringLiteral', isToken: true },
|
||||
{ name: 'closeParenToken', isToken: true, excludeFromAST: true }
|
||||
],
|
||||
isTypeScriptSpecific: true
|
||||
@@ -933,7 +934,7 @@ var definitions = [
|
||||
children: [
|
||||
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||
{ name: 'importKeyword', isToken: true, excludeFromAST: true },
|
||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
{ name: 'identifier', isToken: true },
|
||||
{ name: 'equalsToken', isToken: true, excludeFromAST: true },
|
||||
{ name: 'moduleReference', type: 'IModuleReferenceSyntax' },
|
||||
{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
||||
@@ -947,7 +948,7 @@ var definitions = [
|
||||
children: [
|
||||
{ name: 'exportKeyword', isToken: true, excludeFromAST: true },
|
||||
{ name: 'equalsToken', isToken: true, excludeFromAST: true },
|
||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
{ name: 'identifier', isToken: true },
|
||||
{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
||||
],
|
||||
isTypeScriptSpecific: true
|
||||
@@ -959,7 +960,7 @@ var definitions = [
|
||||
children: [
|
||||
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||
{ name: 'classKeyword', isToken: true, excludeFromAST: true },
|
||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
{ name: 'identifier', isToken: true },
|
||||
{ name: 'typeParameterList', type: 'TypeParameterListSyntax', isOptional: true },
|
||||
{ name: 'heritageClauses', isList: true, elementType: 'HeritageClauseSyntax' },
|
||||
{ name: 'openBraceToken', isToken: true, excludeFromAST: true },
|
||||
@@ -975,7 +976,7 @@ var definitions = [
|
||||
children: [
|
||||
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||
{ name: 'interfaceKeyword', isToken: true, excludeFromAST: true },
|
||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
{ name: 'identifier', isToken: true },
|
||||
{ name: 'typeParameterList', type: 'TypeParameterListSyntax', isOptional: true },
|
||||
{ name: 'heritageClauses', isList: true, elementType: 'HeritageClauseSyntax' },
|
||||
{ name: 'body', type: 'ObjectTypeSyntax' }
|
||||
@@ -1012,7 +1013,8 @@ var definitions = [
|
||||
children: [
|
||||
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken', isTypeScriptSpecific: true },
|
||||
{ name: 'functionKeyword', isToken: true, excludeFromAST: true },
|
||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||
{ name: 'identifier', isToken: true },
|
||||
{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
||||
{ name: 'body', type: 'BlockSyntax | ISyntaxToken', isOptional: true }
|
||||
]
|
||||
@@ -1116,7 +1118,7 @@ var definitions = [
|
||||
children: [
|
||||
{ name: 'left', type: 'INameSyntax' },
|
||||
{ name: 'dotToken', isToken: true, excludeFromAST: true },
|
||||
{ name: 'right', isToken: true, tokenKinds: ['IdentifierName'] }
|
||||
{ name: 'right', isToken: true }
|
||||
],
|
||||
isTypeScriptSpecific: true
|
||||
},
|
||||
@@ -1255,7 +1257,7 @@ var definitions = [
|
||||
children: [
|
||||
{ name: 'dotDotDotToken', isToken: true, isOptional: true, isTypeScriptSpecific: true },
|
||||
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
{ name: 'identifier', isToken: true },
|
||||
{ name: 'questionToken', isToken: true, isOptional: true, isTypeScriptSpecific: true },
|
||||
{ name: 'typeAnnotation', type: 'TypeAnnotationSyntax', isOptional: true, isTypeScriptSpecific: true },
|
||||
{ name: 'equalsValueClause', type: 'EqualsValueClauseSyntax', isOptional: true, isTypeScriptSpecific: true }
|
||||
@@ -1268,7 +1270,7 @@ var definitions = [
|
||||
children: [
|
||||
{ name: 'expression', type: 'ILeftHandSideExpressionSyntax' },
|
||||
{ name: 'dotToken', isToken: true, excludeFromAST: true },
|
||||
{ name: 'name', isToken: true, tokenKinds: ['IdentifierName'] }
|
||||
{ name: 'name', isToken: true }
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1434,7 +1436,7 @@ var definitions = [
|
||||
name: 'TypeParameterSyntax',
|
||||
baseType: 'ISyntaxNode',
|
||||
children: [
|
||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
{ name: 'identifier', isToken: true },
|
||||
{ name: 'constraint', type: 'ConstraintSyntax', isOptional: true }
|
||||
],
|
||||
isTypeScriptSpecific: true
|
||||
@@ -1496,6 +1498,7 @@ var definitions = [
|
||||
interfaces: ['IMemberDeclarationSyntax'],
|
||||
children: [
|
||||
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||
{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||
{ name: 'propertyName', type: 'IPropertyNameSyntax' },
|
||||
{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
||||
{ name: 'body', type: 'BlockSyntax | ISyntaxToken', isOptional: true }
|
||||
@@ -1620,7 +1623,7 @@ var definitions = [
|
||||
interfaces: ['IStatementSyntax'],
|
||||
children: [
|
||||
{ name: 'breakKeyword', isToken: true },
|
||||
{ name: 'identifier', isToken: true, isOptional: true, tokenKinds: ['IdentifierName'] },
|
||||
{ name: 'identifier', isToken: true, isOptional: true },
|
||||
{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
||||
]
|
||||
},
|
||||
@@ -1630,7 +1633,7 @@ var definitions = [
|
||||
interfaces: ['IStatementSyntax'],
|
||||
children: [
|
||||
{ name: 'continueKeyword', isToken: true },
|
||||
{ name: 'identifier', isToken: true, isOptional: true, tokenKinds: ['IdentifierName'] },
|
||||
{ name: 'identifier', isToken: true, isOptional: true },
|
||||
{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
||||
]
|
||||
},
|
||||
@@ -1642,9 +1645,9 @@ var definitions = [
|
||||
{ name: 'forKeyword', isToken: true, excludeFromAST: true },
|
||||
{ name: 'openParenToken', isToken: true, excludeFromAST: true },
|
||||
{ name: 'initializer', type: 'VariableDeclarationSyntax | IExpressionSyntax', isOptional: true },
|
||||
{ name: 'firstSemicolonToken', isToken: true, tokenKinds: ['SemicolonToken'], excludeFromAST: true },
|
||||
{ name: 'firstSemicolonToken', isToken: true, excludeFromAST: true },
|
||||
{ name: 'condition', type: 'IExpressionSyntax', isOptional: true },
|
||||
{ name: 'secondSemicolonToken', isToken: true, tokenKinds: ['SemicolonToken'], excludeFromAST: true },
|
||||
{ name: 'secondSemicolonToken', isToken: true, excludeFromAST: true },
|
||||
{ name: 'incrementor', type: 'IExpressionSyntax', isOptional: true },
|
||||
{ name: 'closeParenToken', isToken: true, excludeFromAST: true },
|
||||
{ name: 'statement', type: 'IStatementSyntax' }
|
||||
@@ -1695,7 +1698,7 @@ var definitions = [
|
||||
children: [
|
||||
{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||
{ name: 'enumKeyword', isToken: true, excludeFromAST: true },
|
||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
{ name: 'identifier', isToken: true },
|
||||
{ name: 'openBraceToken', isToken: true, excludeFromAST: true },
|
||||
{ name: 'enumElements', isSeparatedList: true, elementType: 'EnumElementSyntax' },
|
||||
{ name: 'closeBraceToken', isToken: true, excludeFromAST: true }
|
||||
@@ -1757,6 +1760,7 @@ var definitions = [
|
||||
baseType: 'ISyntaxNode',
|
||||
interfaces: ['IPropertyAssignmentSyntax'],
|
||||
children: [
|
||||
{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||
{ name: 'propertyName', type: 'IPropertyNameSyntax' },
|
||||
{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
||||
{ name: 'block', type: 'BlockSyntax' }
|
||||
@@ -1768,7 +1772,8 @@ var definitions = [
|
||||
interfaces: ['IPrimaryExpressionSyntax'],
|
||||
children: [
|
||||
{ name: 'functionKeyword', isToken: true, excludeFromAST: true },
|
||||
{ name: 'identifier', isToken: true, isOptional: true, tokenKinds: ['IdentifierName'] },
|
||||
{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||
{ name: 'identifier', isToken: true, isOptional: true },
|
||||
{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
||||
{ name: 'block', type: 'BlockSyntax' }
|
||||
]
|
||||
@@ -1798,7 +1803,7 @@ var definitions = [
|
||||
children: [
|
||||
{ name: 'catchKeyword', isToken: true, excludeFromAST: true },
|
||||
{ name: 'openParenToken', isToken: true, excludeFromAST: true },
|
||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
{ name: 'identifier', isToken: true },
|
||||
{ name: 'typeAnnotation', type: 'TypeAnnotationSyntax', isOptional: true, isTypeScriptSpecified: true },
|
||||
{ name: 'closeParenToken', isToken: true, excludeFromAST: true },
|
||||
{ name: 'block', type: 'BlockSyntax' }
|
||||
@@ -1817,7 +1822,7 @@ var definitions = [
|
||||
baseType: 'ISyntaxNode',
|
||||
interfaces: ['IStatementSyntax'],
|
||||
children: [
|
||||
{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
{ name: 'identifier', isToken: true },
|
||||
{ name: 'colonToken', isToken: true, excludeFromAST: true },
|
||||
{ name: 'statement', type: 'IStatementSyntax' }
|
||||
]
|
||||
@@ -1863,6 +1868,16 @@ var definitions = [
|
||||
{ name: 'expression', type: 'IUnaryExpressionSyntax' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'YieldExpressionSyntax',
|
||||
baseType: 'ISyntaxNode',
|
||||
interfaces: ['IExpressionSyntax'],
|
||||
children: [
|
||||
{ name: 'yieldKeyword', isToken: true },
|
||||
{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||
{ name: 'expression', type: 'IExpressionSyntax', isOptional: true }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'DebuggerStatementSyntax',
|
||||
baseType: 'ISyntaxNode',
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
||||
///<reference path='references.ts' />
|
||||
|
||||
module TypeScript {
|
||||
export enum SyntaxConstants {
|
||||
export enum SyntaxNodeConstants {
|
||||
None = 0,
|
||||
|
||||
// Masks that we use to place information about a node into a single int. The first bit tells
|
||||
@@ -15,13 +15,15 @@ module TypeScript {
|
||||
// only be used by the incremental parser if it is parsed in the same strict context as before.
|
||||
// last masks off the part of the int
|
||||
//
|
||||
// The width of the node is stored in the remainder of the int. This allows us up to 256MB
|
||||
// for a node by using all 28 bits. However, in the common case, we'll use less than 28 bits
|
||||
// The width of the node is stored in the remainder of the int. This allows us up to 128MB
|
||||
// for a node by using all 27 bits. However, in the common case, we'll use less than 27 bits
|
||||
// for the width. Thus, the info will be stored in a single int in chakra.
|
||||
NodeDataComputed = 0x00000001, // 0000 0000 0000 0000 0000 0000 0000 0001
|
||||
NodeIncrementallyUnusableMask = 0x00000002, // 0000 0000 0000 0000 0000 0000 0000 0010
|
||||
NodeParsedInStrictModeMask = 0x00000004, // 0000 0000 0000 0000 0000 0000 0000 0100
|
||||
NodeParsedInDisallowInMask = 0x00000008, // 0000 0000 0000 0000 0000 0000 0000 1000
|
||||
NodeFullWidthShift = 4, // 1111 1111 1111 1111 1111 1111 1111 0000
|
||||
DataComputed = 0x00000001, // 0000 0000 0000 0000 0000 0000 0000 0001
|
||||
IncrementallyUnusableMask = 0x00000002, // 0000 0000 0000 0000 0000 0000 0000 0010
|
||||
ParsedInStrictModeContext = 0x00000004, // 0000 0000 0000 0000 0000 0000 0000 0100
|
||||
ParsedInDisallowInContext = 0x00000008, // 0000 0000 0000 0000 0000 0000 0000 1000
|
||||
ParsedInYieldContext = 0x00000010, // 0000 0000 0000 0000 0000 0000 0001 0000
|
||||
ParsedInGeneratorParameterContext = 0x00000020, // 0000 0000 0000 0000 0000 0000 0010 0000
|
||||
FullWidthShift = 1 << 6, // 1111 1111 1111 1111 1111 1111 1100 0000
|
||||
}
|
||||
}
|
||||
+564
-238
File diff suppressed because it is too large
Load Diff
@@ -1018,6 +1018,12 @@ module TypeScript.PrettyPrinter {
|
||||
visitNodeOrToken(this, node.expression);
|
||||
}
|
||||
|
||||
public visitYieldExpression(node: YieldExpressionSyntax): void {
|
||||
this.appendToken(node.yieldKeyword);
|
||||
this.ensureSpace();
|
||||
visitNodeOrToken(this, node.expression);
|
||||
}
|
||||
|
||||
public visitDebuggerStatement(node: DebuggerStatementSyntax): void {
|
||||
this.appendToken(node.debuggerKeyword);
|
||||
this.appendToken(node.semicolonToken);
|
||||
|
||||
@@ -281,7 +281,7 @@ module TypeScript.Scanner {
|
||||
LargeScannerToken.prototype.childCount = 0;
|
||||
|
||||
export interface DiagnosticCallback {
|
||||
(position: number, width: number, key: string, arguments: any[]): void;
|
||||
(position: number, width: number, key: string, arguments?: any[]): void;
|
||||
}
|
||||
|
||||
interface TokenInfo {
|
||||
@@ -1008,7 +1008,7 @@ module TypeScript.Scanner {
|
||||
while (true) {
|
||||
if (index === end) {
|
||||
// Hit the end of the file.
|
||||
reportDiagnostic(end, 0, DiagnosticCode._0_expected, ["`"]);
|
||||
reportDiagnostic(end, 0, DiagnosticCode.Unterminated_template_literal);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1144,10 +1144,7 @@ module TypeScript.Scanner {
|
||||
// term, and it sees one of these then it may restart us asking specifically if we could
|
||||
// scan out a regex.
|
||||
if (allowContextualToken) {
|
||||
var result = tryScanRegularExpressionToken();
|
||||
if (result !== SyntaxKind.None) {
|
||||
return result;
|
||||
}
|
||||
return scanRegularExpressionToken();
|
||||
}
|
||||
|
||||
if (str.charCodeAt(index) === CharacterCodes.equals) {
|
||||
@@ -1159,7 +1156,7 @@ module TypeScript.Scanner {
|
||||
}
|
||||
}
|
||||
|
||||
function tryScanRegularExpressionToken(): SyntaxKind {
|
||||
function scanRegularExpressionToken(): SyntaxKind {
|
||||
var startIndex = index;
|
||||
|
||||
var inEscape = false;
|
||||
@@ -1168,8 +1165,9 @@ module TypeScript.Scanner {
|
||||
var ch = str.charCodeAt(index);
|
||||
|
||||
if (isNaN(ch) || isNewLineCharacter(ch)) {
|
||||
index = startIndex;
|
||||
return SyntaxKind.None;
|
||||
// Hit the end of line, or end of the file. This is not a legal regex.
|
||||
reportDiagnostic(index, 0, DiagnosticCode.Unterminated_regular_expression_literal);
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
@@ -1193,7 +1191,7 @@ module TypeScript.Scanner {
|
||||
continue;
|
||||
|
||||
case CharacterCodes.closeBracket:
|
||||
// If we ever hit a cloe bracket then we're now no longer in a character
|
||||
// If we ever hit a close bracket then we're now no longer in a character
|
||||
// class. If we weren't in a character class to begin with, then this has
|
||||
// no effect.
|
||||
inCharacterClass = false;
|
||||
@@ -1219,7 +1217,7 @@ module TypeScript.Scanner {
|
||||
|
||||
// TODO: The grammar says any identifier part is allowed here. Do we need to support
|
||||
// \u identifiers here? The existing typescript parser does not.
|
||||
while (isIdentifierPartCharacter[str.charCodeAt(index)]) {
|
||||
while (index < end && isIdentifierPartCharacter[str.charCodeAt(index)]) {
|
||||
index++;
|
||||
}
|
||||
|
||||
@@ -1322,7 +1320,7 @@ module TypeScript.Scanner {
|
||||
break;
|
||||
}
|
||||
else if (isNaN(ch) || isNewLineCharacter(ch)) {
|
||||
reportDiagnostic(Math.min(index, end), 1, DiagnosticCode.Missing_close_quote_character, undefined);
|
||||
reportDiagnostic(index, 0, DiagnosticCode.Unterminated_string_literal);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -17,22 +17,40 @@ module TypeScript {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function parsedInStrictMode(node: ISyntaxNode): boolean {
|
||||
export function parsedInStrictModeContext(node: ISyntaxNode): boolean {
|
||||
var info = node.__data;
|
||||
if (info === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (info & SyntaxConstants.NodeParsedInStrictModeMask) !== 0;
|
||||
return (info & SyntaxNodeConstants.ParsedInStrictModeContext) !== 0;
|
||||
}
|
||||
|
||||
export function parsedInDisallowInMode(node: ISyntaxNode): boolean {
|
||||
export function parsedInDisallowInContext(node: ISyntaxNode): boolean {
|
||||
var info = node.__data;
|
||||
if (info === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (info & SyntaxConstants.NodeParsedInDisallowInMask) !== 0;
|
||||
return (info & SyntaxNodeConstants.ParsedInDisallowInContext) !== 0;
|
||||
}
|
||||
|
||||
export function parsedInYieldContext(node: ISyntaxNode): boolean {
|
||||
var info = node.__data;
|
||||
if (info === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (info & SyntaxNodeConstants.ParsedInYieldContext) !== 0;
|
||||
}
|
||||
|
||||
export function parsedInGeneratorParameterContext(node: ISyntaxNode): boolean {
|
||||
var info = node.__data;
|
||||
if (info === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (info & SyntaxNodeConstants.ParsedInGeneratorParameterContext) !== 0;
|
||||
}
|
||||
|
||||
export function previousToken(token: ISyntaxToken): ISyntaxToken {
|
||||
@@ -266,7 +284,7 @@ module TypeScript {
|
||||
}
|
||||
|
||||
var info = data(element);
|
||||
return info >>> SyntaxConstants.NodeFullWidthShift;
|
||||
return (info / SyntaxNodeConstants.FullWidthShift) | 0;
|
||||
}
|
||||
|
||||
export function isIncrementallyUnusable(element: ISyntaxElement): boolean {
|
||||
@@ -274,7 +292,7 @@ module TypeScript {
|
||||
return (<ISyntaxToken>element).isIncrementallyUnusable();
|
||||
}
|
||||
|
||||
return (data(element) & SyntaxConstants.NodeIncrementallyUnusableMask) !== 0;
|
||||
return (data(element) & SyntaxNodeConstants.IncrementallyUnusableMask) !== 0;
|
||||
}
|
||||
|
||||
function data(element: ISyntaxElement): number {
|
||||
@@ -288,7 +306,7 @@ module TypeScript {
|
||||
info = 0;
|
||||
}
|
||||
|
||||
if ((info & SyntaxConstants.NodeDataComputed) === 0) {
|
||||
if ((info & SyntaxNodeConstants.DataComputed) === 0) {
|
||||
info |= computeData(element);
|
||||
dataElement.__data = info;
|
||||
}
|
||||
@@ -297,9 +315,9 @@ module TypeScript {
|
||||
}
|
||||
|
||||
function combineData(fullWidth: number, isIncrementallyUnusable: boolean) {
|
||||
return (fullWidth << SyntaxConstants.NodeFullWidthShift)
|
||||
| (isIncrementallyUnusable ? SyntaxConstants.NodeIncrementallyUnusableMask : 0)
|
||||
| SyntaxConstants.NodeDataComputed;
|
||||
return (fullWidth * SyntaxNodeConstants.FullWidthShift) +
|
||||
(isIncrementallyUnusable ? SyntaxNodeConstants.IncrementallyUnusableMask : 0) +
|
||||
SyntaxNodeConstants.DataComputed;
|
||||
}
|
||||
|
||||
function listComputeData(list: ISyntaxNodeOrToken[]): number {
|
||||
|
||||
@@ -23,7 +23,6 @@ interface IMemberDefinition {
|
||||
isSeparatedList?: boolean;
|
||||
requiresAtLeastOneItem?: boolean;
|
||||
isOptional?: boolean;
|
||||
tokenKinds?: string[];
|
||||
isTypeScriptSpecific: boolean;
|
||||
elementType?: string;
|
||||
}
|
||||
@@ -56,9 +55,9 @@ var definitions:ITypeDefinition[] = [
|
||||
baseType: 'ISyntaxNode',
|
||||
interfaces: ['IModuleReferenceSyntax'],
|
||||
children: [
|
||||
<any>{ name: 'requireKeyword', isToken: true, tokenKinds: ['RequireKeyword'], excludeFromAST: true },
|
||||
<any>{ name: 'requireKeyword', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'openParenToken', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'stringLiteral', isToken: true, tokenKinds: ['StringLiteral'] },
|
||||
<any>{ name: 'stringLiteral', isToken: true },
|
||||
<any>{ name: 'closeParenToken', isToken: true, excludeFromAST: true }
|
||||
],
|
||||
isTypeScriptSpecific: true
|
||||
@@ -79,7 +78,7 @@ var definitions:ITypeDefinition[] = [
|
||||
children: [
|
||||
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||
<any>{ name: 'importKeyword', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
<any>{ name: 'identifier', isToken: true },
|
||||
<any>{ name: 'equalsToken', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'moduleReference', type: 'IModuleReferenceSyntax' },
|
||||
<any>{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
||||
@@ -93,7 +92,7 @@ var definitions:ITypeDefinition[] = [
|
||||
children: [
|
||||
<any>{ name: 'exportKeyword', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'equalsToken', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
<any>{ name: 'identifier', isToken: true },
|
||||
<any>{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
||||
],
|
||||
isTypeScriptSpecific: true
|
||||
@@ -105,7 +104,7 @@ var definitions:ITypeDefinition[] = [
|
||||
children: [
|
||||
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||
<any>{ name: 'classKeyword', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
<any>{ name: 'identifier', isToken: true },
|
||||
<any>{ name: 'typeParameterList', type: 'TypeParameterListSyntax', isOptional: true },
|
||||
<any>{ name: 'heritageClauses', isList: true, elementType: 'HeritageClauseSyntax' },
|
||||
<any>{ name: 'openBraceToken', isToken: true, excludeFromAST: true },
|
||||
@@ -121,7 +120,7 @@ var definitions:ITypeDefinition[] = [
|
||||
children: [
|
||||
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||
<any>{ name: 'interfaceKeyword', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
<any>{ name: 'identifier', isToken: true },
|
||||
<any>{ name: 'typeParameterList', type: 'TypeParameterListSyntax', isOptional: true },
|
||||
<any>{ name: 'heritageClauses', isList: true, elementType: 'HeritageClauseSyntax' },
|
||||
<any>{ name: 'body', type: 'ObjectTypeSyntax' }
|
||||
@@ -158,7 +157,8 @@ var definitions:ITypeDefinition[] = [
|
||||
children: [
|
||||
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken', isTypeScriptSpecific: true },
|
||||
<any>{ name: 'functionKeyword', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
<any>{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||
<any>{ name: 'identifier', isToken: true },
|
||||
<any>{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
||||
<any>{ name: 'body', type: 'BlockSyntax | ISyntaxToken', isOptional: true }
|
||||
]
|
||||
@@ -262,7 +262,7 @@ var definitions:ITypeDefinition[] = [
|
||||
children: [
|
||||
<any>{ name: 'left', type: 'INameSyntax' },
|
||||
<any>{ name: 'dotToken', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'right', isToken: true, tokenKinds:['IdentifierName'] }
|
||||
<any>{ name: 'right', isToken: true }
|
||||
],
|
||||
// Qualified names only show up in Types, which are TypeScript specific. Note that a dotted
|
||||
// expression (like A.B.Foo()) is a MemberAccessExpression, not a QualifiedName.
|
||||
@@ -403,7 +403,7 @@ var definitions:ITypeDefinition[] = [
|
||||
children: [
|
||||
<any>{ name: 'dotDotDotToken', isToken: true, isOptional: true, isTypeScriptSpecific: true },
|
||||
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
<any>{ name: 'identifier', isToken: true },
|
||||
<any>{ name: 'questionToken', isToken: true, isOptional: true, isTypeScriptSpecific: true },
|
||||
<any>{ name: 'typeAnnotation', type: 'TypeAnnotationSyntax', isOptional: true, isTypeScriptSpecific: true },
|
||||
<any>{ name: 'equalsValueClause', type: 'EqualsValueClauseSyntax', isOptional: true, isTypeScriptSpecific: true }
|
||||
@@ -416,7 +416,7 @@ var definitions:ITypeDefinition[] = [
|
||||
children: [
|
||||
<any>{ name: 'expression', type: 'ILeftHandSideExpressionSyntax' },
|
||||
<any>{ name: 'dotToken', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'name', isToken: true, tokenKinds: ['IdentifierName'] }
|
||||
<any>{ name: 'name', isToken: true }
|
||||
]
|
||||
},
|
||||
<any>{
|
||||
@@ -582,7 +582,7 @@ var definitions:ITypeDefinition[] = [
|
||||
name: 'TypeParameterSyntax',
|
||||
baseType: 'ISyntaxNode',
|
||||
children: [
|
||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
<any>{ name: 'identifier', isToken: true },
|
||||
<any>{ name: 'constraint', type: 'ConstraintSyntax', isOptional: true }
|
||||
],
|
||||
isTypeScriptSpecific: true
|
||||
@@ -645,6 +645,7 @@ var definitions:ITypeDefinition[] = [
|
||||
interfaces: ['IMemberDeclarationSyntax'],
|
||||
children: [
|
||||
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||
<any>{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||
<any>{ name: 'propertyName', type: 'IPropertyNameSyntax' },
|
||||
<any>{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
||||
<any>{ name: 'body', type: 'BlockSyntax | ISyntaxToken', isOptional: true }
|
||||
@@ -769,7 +770,7 @@ var definitions:ITypeDefinition[] = [
|
||||
interfaces: ['IStatementSyntax'],
|
||||
children: [
|
||||
<any>{ name: 'breakKeyword', isToken: true },
|
||||
<any>{ name: 'identifier', isToken: true, isOptional: true, tokenKinds: ['IdentifierName'] },
|
||||
<any>{ name: 'identifier', isToken: true, isOptional: true },
|
||||
<any>{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
||||
]
|
||||
},
|
||||
@@ -779,7 +780,7 @@ var definitions:ITypeDefinition[] = [
|
||||
interfaces: ['IStatementSyntax'],
|
||||
children: [
|
||||
<any>{ name: 'continueKeyword', isToken: true },
|
||||
<any>{ name: 'identifier', isToken: true, isOptional: true, tokenKinds: ['IdentifierName'] },
|
||||
<any>{ name: 'identifier', isToken: true, isOptional: true },
|
||||
<any>{ name: 'semicolonToken', isToken: true, isOptional: true, excludeFromAST: true }
|
||||
]
|
||||
},
|
||||
@@ -791,9 +792,9 @@ var definitions:ITypeDefinition[] = [
|
||||
<any>{ name: 'forKeyword', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'openParenToken', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'initializer', type: 'VariableDeclarationSyntax | IExpressionSyntax', isOptional: true },
|
||||
<any>{ name: 'firstSemicolonToken', isToken: true, tokenKinds: ['SemicolonToken'], excludeFromAST: true },
|
||||
<any>{ name: 'firstSemicolonToken', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'condition', type: 'IExpressionSyntax', isOptional: true },
|
||||
<any>{ name: 'secondSemicolonToken', isToken: true, tokenKinds: ['SemicolonToken'], excludeFromAST: true },
|
||||
<any>{ name: 'secondSemicolonToken', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'incrementor', type: 'IExpressionSyntax', isOptional: true },
|
||||
<any>{ name: 'closeParenToken', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'statement', type: 'IStatementSyntax' }
|
||||
@@ -844,7 +845,7 @@ var definitions:ITypeDefinition[] = [
|
||||
children: [
|
||||
<any>{ name: 'modifiers', isList: true, elementType: 'ISyntaxToken' },
|
||||
<any>{ name: 'enumKeyword', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
<any>{ name: 'identifier', isToken: true },
|
||||
<any>{ name: 'openBraceToken', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'enumElements', isSeparatedList: true, elementType: 'EnumElementSyntax' },
|
||||
<any>{ name: 'closeBraceToken', isToken: true, excludeFromAST: true }
|
||||
@@ -906,6 +907,7 @@ var definitions:ITypeDefinition[] = [
|
||||
baseType: 'ISyntaxNode',
|
||||
interfaces: ['IPropertyAssignmentSyntax'],
|
||||
children: [
|
||||
<any>{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||
<any>{ name: 'propertyName', type: 'IPropertyNameSyntax' },
|
||||
<any>{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
||||
<any>{ name: 'block', type: 'BlockSyntax' }
|
||||
@@ -917,7 +919,8 @@ var definitions:ITypeDefinition[] = [
|
||||
interfaces: ['IPrimaryExpressionSyntax'],
|
||||
children: [
|
||||
<any>{ name: 'functionKeyword', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'identifier', isToken: true, isOptional: true, tokenKinds: ['IdentifierName'] },
|
||||
<any>{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||
<any>{ name: 'identifier', isToken: true, isOptional: true },
|
||||
<any>{ name: 'callSignature', type: 'CallSignatureSyntax' },
|
||||
<any>{ name: 'block', type: 'BlockSyntax' }]
|
||||
},
|
||||
@@ -944,7 +947,7 @@ var definitions:ITypeDefinition[] = [
|
||||
children: [
|
||||
<any>{ name: 'catchKeyword', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'openParenToken', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
<any>{ name: 'identifier', isToken: true },
|
||||
<any>{ name: 'typeAnnotation', type: 'TypeAnnotationSyntax', isOptional: true, isTypeScriptSpecified: true },
|
||||
<any>{ name: 'closeParenToken', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'block', type: 'BlockSyntax' }]
|
||||
@@ -961,7 +964,7 @@ var definitions:ITypeDefinition[] = [
|
||||
baseType: 'ISyntaxNode',
|
||||
interfaces: ['IStatementSyntax'],
|
||||
children: [
|
||||
<any>{ name: 'identifier', isToken: true, tokenKinds: ['IdentifierName'] },
|
||||
<any>{ name: 'identifier', isToken: true },
|
||||
<any>{ name: 'colonToken', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'statement', type: 'IStatementSyntax' }]
|
||||
},
|
||||
@@ -1002,6 +1005,15 @@ var definitions:ITypeDefinition[] = [
|
||||
<any>{ name: 'voidKeyword', isToken: true, excludeFromAST: true },
|
||||
<any>{ name: 'expression', type: 'IUnaryExpressionSyntax' }]
|
||||
},
|
||||
<any>{
|
||||
name: 'YieldExpressionSyntax',
|
||||
baseType: 'ISyntaxNode',
|
||||
interfaces: ['IExpressionSyntax'],
|
||||
children: [
|
||||
<any>{ name: 'yieldKeyword', isToken: true },
|
||||
<any>{ name: 'asterixToken', isToken: true, isOptional: true },
|
||||
<any>{ name: 'expression', type: 'IExpressionSyntax', isOptional: true }]
|
||||
},
|
||||
<any>{
|
||||
name: 'DebuggerStatementSyntax',
|
||||
baseType: 'ISyntaxNode',
|
||||
|
||||
@@ -92,11 +92,12 @@ module TypeScript {
|
||||
export interface FunctionDeclarationSyntax extends ISyntaxNode, IStatementSyntax {
|
||||
modifiers: ISyntaxToken[];
|
||||
functionKeyword: ISyntaxToken;
|
||||
asterixToken: ISyntaxToken;
|
||||
identifier: ISyntaxToken;
|
||||
callSignature: CallSignatureSyntax;
|
||||
body: BlockSyntax | ISyntaxToken;
|
||||
}
|
||||
export interface FunctionDeclarationConstructor { new (data: number, modifiers: ISyntaxToken[], functionKeyword: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, body: BlockSyntax | ISyntaxToken): FunctionDeclarationSyntax }
|
||||
export interface FunctionDeclarationConstructor { new (data: number, modifiers: ISyntaxToken[], functionKeyword: ISyntaxToken, asterixToken: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, body: BlockSyntax | ISyntaxToken): FunctionDeclarationSyntax }
|
||||
|
||||
export interface ModuleDeclarationSyntax extends ISyntaxNode, IModuleElementSyntax {
|
||||
modifiers: ISyntaxToken[];
|
||||
@@ -150,11 +151,12 @@ module TypeScript {
|
||||
|
||||
export interface MemberFunctionDeclarationSyntax extends ISyntaxNode, IMemberDeclarationSyntax {
|
||||
modifiers: ISyntaxToken[];
|
||||
asterixToken: ISyntaxToken;
|
||||
propertyName: IPropertyNameSyntax;
|
||||
callSignature: CallSignatureSyntax;
|
||||
body: BlockSyntax | ISyntaxToken;
|
||||
}
|
||||
export interface MemberFunctionDeclarationConstructor { new (data: number, modifiers: ISyntaxToken[], propertyName: IPropertyNameSyntax, callSignature: CallSignatureSyntax, body: BlockSyntax | ISyntaxToken): MemberFunctionDeclarationSyntax }
|
||||
export interface MemberFunctionDeclarationConstructor { new (data: number, modifiers: ISyntaxToken[], asterixToken: ISyntaxToken, propertyName: IPropertyNameSyntax, callSignature: CallSignatureSyntax, body: BlockSyntax | ISyntaxToken): MemberFunctionDeclarationSyntax }
|
||||
|
||||
export interface MemberVariableDeclarationSyntax extends ISyntaxNode, IMemberDeclarationSyntax {
|
||||
modifiers: ISyntaxToken[];
|
||||
@@ -498,11 +500,12 @@ module TypeScript {
|
||||
|
||||
export interface FunctionExpressionSyntax extends ISyntaxNode, IPrimaryExpressionSyntax {
|
||||
functionKeyword: ISyntaxToken;
|
||||
asterixToken: ISyntaxToken;
|
||||
identifier: ISyntaxToken;
|
||||
callSignature: CallSignatureSyntax;
|
||||
block: BlockSyntax;
|
||||
}
|
||||
export interface FunctionExpressionConstructor { new (data: number, functionKeyword: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax): FunctionExpressionSyntax }
|
||||
export interface FunctionExpressionConstructor { new (data: number, functionKeyword: ISyntaxToken, asterixToken: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax): FunctionExpressionSyntax }
|
||||
|
||||
export interface OmittedExpressionSyntax extends ISyntaxNode, IExpressionSyntax {
|
||||
}
|
||||
@@ -520,6 +523,13 @@ module TypeScript {
|
||||
}
|
||||
export interface TemplateAccessExpressionConstructor { new (data: number, expression: ILeftHandSideExpressionSyntax, templateExpression: IPrimaryExpressionSyntax): TemplateAccessExpressionSyntax }
|
||||
|
||||
export interface YieldExpressionSyntax extends ISyntaxNode, IExpressionSyntax {
|
||||
yieldKeyword: ISyntaxToken;
|
||||
asterixToken: ISyntaxToken;
|
||||
expression: IExpressionSyntax;
|
||||
}
|
||||
export interface YieldExpressionConstructor { new (data: number, yieldKeyword: ISyntaxToken, asterixToken: ISyntaxToken, expression: IExpressionSyntax): YieldExpressionSyntax }
|
||||
|
||||
export interface VariableDeclarationSyntax extends ISyntaxNode {
|
||||
varKeyword: ISyntaxToken;
|
||||
variableDeclarators: ISeparatedSyntaxList<VariableDeclaratorSyntax>;
|
||||
@@ -637,11 +647,12 @@ module TypeScript {
|
||||
export interface SimplePropertyAssignmentConstructor { new (data: number, propertyName: IPropertyNameSyntax, colonToken: ISyntaxToken, expression: IExpressionSyntax): SimplePropertyAssignmentSyntax }
|
||||
|
||||
export interface FunctionPropertyAssignmentSyntax extends ISyntaxNode, IPropertyAssignmentSyntax {
|
||||
asterixToken: ISyntaxToken;
|
||||
propertyName: IPropertyNameSyntax;
|
||||
callSignature: CallSignatureSyntax;
|
||||
block: BlockSyntax;
|
||||
}
|
||||
export interface FunctionPropertyAssignmentConstructor { new (data: number, propertyName: IPropertyNameSyntax, callSignature: CallSignatureSyntax, block: BlockSyntax): FunctionPropertyAssignmentSyntax }
|
||||
export interface FunctionPropertyAssignmentConstructor { new (data: number, asterixToken: ISyntaxToken, propertyName: IPropertyNameSyntax, callSignature: CallSignatureSyntax, block: BlockSyntax): FunctionPropertyAssignmentSyntax }
|
||||
|
||||
export interface ParameterSyntax extends ISyntaxNode {
|
||||
dotDotDotToken: ISyntaxToken;
|
||||
|
||||
@@ -234,6 +234,7 @@ module TypeScript {
|
||||
OmittedExpression,
|
||||
TemplateExpression,
|
||||
TemplateAccessExpression,
|
||||
YieldExpression,
|
||||
|
||||
// Variable declarations
|
||||
VariableDeclaration,
|
||||
|
||||
@@ -238,28 +238,31 @@ module TypeScript {
|
||||
}
|
||||
}
|
||||
|
||||
export var FunctionDeclarationSyntax: FunctionDeclarationConstructor = <any>function(data: number, modifiers: ISyntaxToken[], functionKeyword: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, body: BlockSyntax | ISyntaxToken) {
|
||||
export var FunctionDeclarationSyntax: FunctionDeclarationConstructor = <any>function(data: number, modifiers: ISyntaxToken[], functionKeyword: ISyntaxToken, asterixToken: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, body: BlockSyntax | ISyntaxToken) {
|
||||
if (data) { this.__data = data; }
|
||||
this.modifiers = modifiers,
|
||||
this.functionKeyword = functionKeyword,
|
||||
this.asterixToken = asterixToken,
|
||||
this.identifier = identifier,
|
||||
this.callSignature = callSignature,
|
||||
this.body = body,
|
||||
modifiers.parent = this,
|
||||
functionKeyword.parent = this,
|
||||
asterixToken && (asterixToken.parent = this),
|
||||
identifier.parent = this,
|
||||
callSignature.parent = this,
|
||||
body && (body.parent = this);
|
||||
};
|
||||
FunctionDeclarationSyntax.prototype.kind = SyntaxKind.FunctionDeclaration;
|
||||
FunctionDeclarationSyntax.prototype.childCount = 5;
|
||||
FunctionDeclarationSyntax.prototype.childCount = 6;
|
||||
FunctionDeclarationSyntax.prototype.childAt = function(index: number): ISyntaxElement {
|
||||
switch (index) {
|
||||
case 0: return this.modifiers;
|
||||
case 1: return this.functionKeyword;
|
||||
case 2: return this.identifier;
|
||||
case 3: return this.callSignature;
|
||||
case 4: return this.body;
|
||||
case 2: return this.asterixToken;
|
||||
case 3: return this.identifier;
|
||||
case 4: return this.callSignature;
|
||||
case 5: return this.body;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,25 +406,28 @@ module TypeScript {
|
||||
}
|
||||
}
|
||||
|
||||
export var MemberFunctionDeclarationSyntax: MemberFunctionDeclarationConstructor = <any>function(data: number, modifiers: ISyntaxToken[], propertyName: IPropertyNameSyntax, callSignature: CallSignatureSyntax, body: BlockSyntax | ISyntaxToken) {
|
||||
export var MemberFunctionDeclarationSyntax: MemberFunctionDeclarationConstructor = <any>function(data: number, modifiers: ISyntaxToken[], asterixToken: ISyntaxToken, propertyName: IPropertyNameSyntax, callSignature: CallSignatureSyntax, body: BlockSyntax | ISyntaxToken) {
|
||||
if (data) { this.__data = data; }
|
||||
this.modifiers = modifiers,
|
||||
this.asterixToken = asterixToken,
|
||||
this.propertyName = propertyName,
|
||||
this.callSignature = callSignature,
|
||||
this.body = body,
|
||||
modifiers.parent = this,
|
||||
asterixToken && (asterixToken.parent = this),
|
||||
propertyName.parent = this,
|
||||
callSignature.parent = this,
|
||||
body && (body.parent = this);
|
||||
};
|
||||
MemberFunctionDeclarationSyntax.prototype.kind = SyntaxKind.MemberFunctionDeclaration;
|
||||
MemberFunctionDeclarationSyntax.prototype.childCount = 4;
|
||||
MemberFunctionDeclarationSyntax.prototype.childCount = 5;
|
||||
MemberFunctionDeclarationSyntax.prototype.childAt = function(index: number): ISyntaxElement {
|
||||
switch (index) {
|
||||
case 0: return this.modifiers;
|
||||
case 1: return this.propertyName;
|
||||
case 2: return this.callSignature;
|
||||
case 3: return this.body;
|
||||
case 1: return this.asterixToken;
|
||||
case 2: return this.propertyName;
|
||||
case 3: return this.callSignature;
|
||||
case 4: return this.body;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1355,25 +1361,28 @@ module TypeScript {
|
||||
}
|
||||
}
|
||||
|
||||
export var FunctionExpressionSyntax: FunctionExpressionConstructor = <any>function(data: number, functionKeyword: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax) {
|
||||
export var FunctionExpressionSyntax: FunctionExpressionConstructor = <any>function(data: number, functionKeyword: ISyntaxToken, asterixToken: ISyntaxToken, identifier: ISyntaxToken, callSignature: CallSignatureSyntax, block: BlockSyntax) {
|
||||
if (data) { this.__data = data; }
|
||||
this.functionKeyword = functionKeyword,
|
||||
this.asterixToken = asterixToken,
|
||||
this.identifier = identifier,
|
||||
this.callSignature = callSignature,
|
||||
this.block = block,
|
||||
functionKeyword.parent = this,
|
||||
asterixToken && (asterixToken.parent = this),
|
||||
identifier && (identifier.parent = this),
|
||||
callSignature.parent = this,
|
||||
block.parent = this;
|
||||
};
|
||||
FunctionExpressionSyntax.prototype.kind = SyntaxKind.FunctionExpression;
|
||||
FunctionExpressionSyntax.prototype.childCount = 4;
|
||||
FunctionExpressionSyntax.prototype.childCount = 5;
|
||||
FunctionExpressionSyntax.prototype.childAt = function(index: number): ISyntaxElement {
|
||||
switch (index) {
|
||||
case 0: return this.functionKeyword;
|
||||
case 1: return this.identifier;
|
||||
case 2: return this.callSignature;
|
||||
case 3: return this.block;
|
||||
case 1: return this.asterixToken;
|
||||
case 2: return this.identifier;
|
||||
case 3: return this.callSignature;
|
||||
case 4: return this.block;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1418,6 +1427,25 @@ module TypeScript {
|
||||
}
|
||||
}
|
||||
|
||||
export var YieldExpressionSyntax: YieldExpressionConstructor = <any>function(data: number, yieldKeyword: ISyntaxToken, asterixToken: ISyntaxToken, expression: IExpressionSyntax) {
|
||||
if (data) { this.__data = data; }
|
||||
this.yieldKeyword = yieldKeyword,
|
||||
this.asterixToken = asterixToken,
|
||||
this.expression = expression,
|
||||
yieldKeyword.parent = this,
|
||||
asterixToken && (asterixToken.parent = this),
|
||||
expression && (expression.parent = this);
|
||||
};
|
||||
YieldExpressionSyntax.prototype.kind = SyntaxKind.YieldExpression;
|
||||
YieldExpressionSyntax.prototype.childCount = 3;
|
||||
YieldExpressionSyntax.prototype.childAt = function(index: number): ISyntaxElement {
|
||||
switch (index) {
|
||||
case 0: return this.yieldKeyword;
|
||||
case 1: return this.asterixToken;
|
||||
case 2: return this.expression;
|
||||
}
|
||||
}
|
||||
|
||||
export var VariableDeclarationSyntax: VariableDeclarationConstructor = <any>function(data: number, varKeyword: ISyntaxToken, variableDeclarators: ISeparatedSyntaxList<VariableDeclaratorSyntax>) {
|
||||
if (data) { this.__data = data; }
|
||||
this.varKeyword = varKeyword,
|
||||
@@ -1732,22 +1760,25 @@ module TypeScript {
|
||||
}
|
||||
}
|
||||
|
||||
export var FunctionPropertyAssignmentSyntax: FunctionPropertyAssignmentConstructor = <any>function(data: number, propertyName: IPropertyNameSyntax, callSignature: CallSignatureSyntax, block: BlockSyntax) {
|
||||
export var FunctionPropertyAssignmentSyntax: FunctionPropertyAssignmentConstructor = <any>function(data: number, asterixToken: ISyntaxToken, propertyName: IPropertyNameSyntax, callSignature: CallSignatureSyntax, block: BlockSyntax) {
|
||||
if (data) { this.__data = data; }
|
||||
this.asterixToken = asterixToken,
|
||||
this.propertyName = propertyName,
|
||||
this.callSignature = callSignature,
|
||||
this.block = block,
|
||||
asterixToken && (asterixToken.parent = this),
|
||||
propertyName.parent = this,
|
||||
callSignature.parent = this,
|
||||
block.parent = this;
|
||||
};
|
||||
FunctionPropertyAssignmentSyntax.prototype.kind = SyntaxKind.FunctionPropertyAssignment;
|
||||
FunctionPropertyAssignmentSyntax.prototype.childCount = 3;
|
||||
FunctionPropertyAssignmentSyntax.prototype.childCount = 4;
|
||||
FunctionPropertyAssignmentSyntax.prototype.childAt = function(index: number): ISyntaxElement {
|
||||
switch (index) {
|
||||
case 0: return this.propertyName;
|
||||
case 1: return this.callSignature;
|
||||
case 2: return this.block;
|
||||
case 0: return this.asterixToken;
|
||||
case 1: return this.propertyName;
|
||||
case 2: return this.callSignature;
|
||||
case 3: return this.block;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1297,7 +1297,7 @@ module TypeScript {
|
||||
}
|
||||
|
||||
private checkForWithInStrictMode(node: WithStatementSyntax): boolean {
|
||||
if (parsedInStrictMode(node)) {
|
||||
if (parsedInStrictModeContext(node)) {
|
||||
this.pushDiagnostic(firstToken(node), DiagnosticCode.with_statements_are_not_allowed_in_strict_mode);
|
||||
return true;
|
||||
}
|
||||
@@ -1509,7 +1509,7 @@ module TypeScript {
|
||||
}
|
||||
|
||||
public visitPrefixUnaryExpression(node: PrefixUnaryExpressionSyntax): void {
|
||||
if (parsedInStrictMode(node) && this.isPreIncrementOrDecrementExpression(node) && this.isEvalOrArguments(node.operand)) {
|
||||
if (parsedInStrictModeContext(node) && this.isPreIncrementOrDecrementExpression(node) && this.isEvalOrArguments(node.operand)) {
|
||||
this.pushDiagnostic(node.operatorToken, DiagnosticCode.Invalid_use_of_0_in_strict_mode, [this.getEvalOrArguments(node.operand)]);
|
||||
}
|
||||
|
||||
@@ -1517,7 +1517,7 @@ module TypeScript {
|
||||
}
|
||||
|
||||
public visitPostfixUnaryExpression(node: PostfixUnaryExpressionSyntax): void {
|
||||
if (parsedInStrictMode(node) && this.isEvalOrArguments(node.operand)) {
|
||||
if (parsedInStrictModeContext(node) && this.isEvalOrArguments(node.operand)) {
|
||||
this.pushDiagnostic(node.operatorToken, DiagnosticCode.Invalid_use_of_0_in_strict_mode, [this.getEvalOrArguments(node.operand)]);
|
||||
}
|
||||
|
||||
@@ -1534,7 +1534,7 @@ module TypeScript {
|
||||
|
||||
private checkForDisallowedEvalOrArguments(node: ISyntaxNode, token: ISyntaxToken): boolean {
|
||||
if (token) {
|
||||
if (parsedInStrictMode(node) && this.isEvalOrArguments(token)) {
|
||||
if (parsedInStrictModeContext(node) && this.isEvalOrArguments(token)) {
|
||||
this.pushDiagnostic(token, DiagnosticCode.Invalid_use_of_0_in_strict_mode, [this.getEvalOrArguments(token)]);
|
||||
return true;
|
||||
}
|
||||
@@ -1554,16 +1554,25 @@ module TypeScript {
|
||||
}
|
||||
|
||||
public visitDeleteExpression(node: DeleteExpressionSyntax): void {
|
||||
if (parsedInStrictMode(node) && node.expression.kind === SyntaxKind.IdentifierName) {
|
||||
this.pushDiagnostic(firstToken(node), DiagnosticCode.delete_cannot_be_called_on_an_identifier_in_strict_mode);
|
||||
if (parsedInStrictModeContext(node) && node.expression.kind === SyntaxKind.IdentifierName) {
|
||||
this.pushDiagnostic(node.deleteKeyword, DiagnosticCode.delete_cannot_be_called_on_an_identifier_in_strict_mode);
|
||||
return;
|
||||
}
|
||||
|
||||
super.visitDeleteExpression(node);
|
||||
}
|
||||
|
||||
public visitYieldExpression(node: YieldExpressionSyntax): void {
|
||||
if (!parsedInYieldContext(node)) {
|
||||
this.pushDiagnostic(node.yieldKeyword, DiagnosticCode.yield_expression_must_be_contained_within_a_generator_declaration);
|
||||
return;
|
||||
}
|
||||
|
||||
super.visitYieldExpression(node);
|
||||
}
|
||||
|
||||
private checkIllegalAssignment(node: BinaryExpressionSyntax): boolean {
|
||||
if (parsedInStrictMode(node) && SyntaxFacts.isAssignmentOperatorToken(node.operatorToken.kind) && this.isEvalOrArguments(node.left)) {
|
||||
if (parsedInStrictModeContext(node) && SyntaxFacts.isAssignmentOperatorToken(node.operatorToken.kind) && this.isEvalOrArguments(node.left)) {
|
||||
this.pushDiagnostic(node.operatorToken, DiagnosticCode.Invalid_use_of_0_in_strict_mode, [this.getEvalOrArguments(node.left)]);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ module TypeScript {
|
||||
case SyntaxKind.OmittedExpression: return visitor.visitOmittedExpression(<OmittedExpressionSyntax>element);
|
||||
case SyntaxKind.TemplateExpression: return visitor.visitTemplateExpression(<TemplateExpressionSyntax>element);
|
||||
case SyntaxKind.TemplateAccessExpression: return visitor.visitTemplateAccessExpression(<TemplateAccessExpressionSyntax>element);
|
||||
case SyntaxKind.YieldExpression: return visitor.visitYieldExpression(<YieldExpressionSyntax>element);
|
||||
case SyntaxKind.VariableDeclaration: return visitor.visitVariableDeclaration(<VariableDeclarationSyntax>element);
|
||||
case SyntaxKind.VariableDeclarator: return visitor.visitVariableDeclarator(<VariableDeclaratorSyntax>element);
|
||||
case SyntaxKind.ArgumentList: return visitor.visitArgumentList(<ArgumentListSyntax>element);
|
||||
@@ -170,6 +171,7 @@ module TypeScript {
|
||||
visitOmittedExpression(node: OmittedExpressionSyntax): any;
|
||||
visitTemplateExpression(node: TemplateExpressionSyntax): any;
|
||||
visitTemplateAccessExpression(node: TemplateAccessExpressionSyntax): any;
|
||||
visitYieldExpression(node: YieldExpressionSyntax): any;
|
||||
visitVariableDeclaration(node: VariableDeclarationSyntax): any;
|
||||
visitVariableDeclarator(node: VariableDeclaratorSyntax): any;
|
||||
visitArgumentList(node: ArgumentListSyntax): any;
|
||||
|
||||
@@ -97,6 +97,7 @@ module TypeScript {
|
||||
public visitFunctionDeclaration(node: FunctionDeclarationSyntax): void {
|
||||
this.visitList(node.modifiers);
|
||||
this.visitToken(node.functionKeyword);
|
||||
this.visitOptionalToken(node.asterixToken);
|
||||
this.visitToken(node.identifier);
|
||||
visitNodeOrToken(this, node.callSignature);
|
||||
visitNodeOrToken(this, node.body);
|
||||
@@ -149,6 +150,7 @@ module TypeScript {
|
||||
|
||||
public visitMemberFunctionDeclaration(node: MemberFunctionDeclarationSyntax): void {
|
||||
this.visitList(node.modifiers);
|
||||
this.visitOptionalToken(node.asterixToken);
|
||||
visitNodeOrToken(this, node.propertyName);
|
||||
visitNodeOrToken(this, node.callSignature);
|
||||
visitNodeOrToken(this, node.body);
|
||||
@@ -451,6 +453,7 @@ module TypeScript {
|
||||
|
||||
public visitFunctionExpression(node: FunctionExpressionSyntax): void {
|
||||
this.visitToken(node.functionKeyword);
|
||||
this.visitOptionalToken(node.asterixToken);
|
||||
this.visitOptionalToken(node.identifier);
|
||||
visitNodeOrToken(this, node.callSignature);
|
||||
visitNodeOrToken(this, node.block);
|
||||
@@ -469,6 +472,12 @@ module TypeScript {
|
||||
visitNodeOrToken(this, node.templateExpression);
|
||||
}
|
||||
|
||||
public visitYieldExpression(node: YieldExpressionSyntax): void {
|
||||
this.visitToken(node.yieldKeyword);
|
||||
this.visitOptionalToken(node.asterixToken);
|
||||
visitNodeOrToken(this, node.expression);
|
||||
}
|
||||
|
||||
public visitVariableDeclaration(node: VariableDeclarationSyntax): void {
|
||||
this.visitToken(node.varKeyword);
|
||||
this.visitList(node.variableDeclarators);
|
||||
@@ -569,6 +578,7 @@ module TypeScript {
|
||||
}
|
||||
|
||||
public visitFunctionPropertyAssignment(node: FunctionPropertyAssignmentSyntax): void {
|
||||
this.visitOptionalToken(node.asterixToken);
|
||||
visitNodeOrToken(this, node.propertyName);
|
||||
visitNodeOrToken(this, node.callSignature);
|
||||
visitNodeOrToken(this, node.block);
|
||||
|
||||
@@ -0,0 +1,296 @@
|
||||
module ts {
|
||||
export class TextSpan {
|
||||
private _start: number;
|
||||
private _length: number;
|
||||
|
||||
/**
|
||||
* Creates a TextSpan instance beginning with the position Start and having the Length
|
||||
* specified with length.
|
||||
*/
|
||||
constructor(start: number, length: number) {
|
||||
Debug.assert(start >= 0, "start");
|
||||
Debug.assert(length >= 0, "length");
|
||||
|
||||
this._start = start;
|
||||
this._length = length;
|
||||
}
|
||||
|
||||
public toJSON(key: any): any {
|
||||
return { start: this._start, length: this._length };
|
||||
}
|
||||
|
||||
public start(): number {
|
||||
return this._start;
|
||||
}
|
||||
|
||||
public length(): number {
|
||||
return this._length;
|
||||
}
|
||||
|
||||
public end(): number {
|
||||
return this._start + this._length;
|
||||
}
|
||||
|
||||
public isEmpty(): boolean {
|
||||
return this._length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the position lies within the span. Returns true if the position is greater than or equal to Start and strictly less
|
||||
* than End, otherwise false.
|
||||
* @param position The position to check.
|
||||
*/
|
||||
public containsPosition(position: number): boolean {
|
||||
return position >= this._start && position < this.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether span falls completely within this span. Returns true if the specified span falls completely within this span, otherwise false.
|
||||
* @param span The span to check.
|
||||
*/
|
||||
public containsTextSpan(span: TextSpan): boolean {
|
||||
return span._start >= this._start && span.end() <= this.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given span overlaps this span. Two spans are considered to overlap
|
||||
* if they have positions in common and neither is empty. Empty spans do not overlap with any
|
||||
* other span. Returns true if the spans overlap, false otherwise.
|
||||
* @param span The span to check.
|
||||
*/
|
||||
public overlapsWith(span: TextSpan): boolean {
|
||||
var overlapStart = Math.max(this._start, span._start);
|
||||
var overlapEnd = Math.min(this.end(), span.end());
|
||||
|
||||
return overlapStart < overlapEnd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the overlap with the given span, or undefined if there is no overlap.
|
||||
* @param span The span to check.
|
||||
*/
|
||||
public overlap(span: TextSpan): TextSpan {
|
||||
var overlapStart = Math.max(this._start, span._start);
|
||||
var overlapEnd = Math.min(this.end(), span.end());
|
||||
|
||||
if (overlapStart < overlapEnd) {
|
||||
return TextSpan.fromBounds(overlapStart, overlapEnd);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether span intersects this span. Two spans are considered to
|
||||
* intersect if they have positions in common or the end of one span
|
||||
* coincides with the start of the other span. Returns true if the spans intersect, false otherwise.
|
||||
* @param The span to check.
|
||||
*/
|
||||
public intersectsWithTextSpan(span: TextSpan): boolean {
|
||||
return span._start <= this.end() && span.end() >= this._start;
|
||||
}
|
||||
|
||||
public intersectsWith(start: number, length: number): boolean {
|
||||
var end = start + length;
|
||||
return start <= this.end() && end >= this._start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given position intersects this span.
|
||||
* A position is considered to intersect if it is between the start and
|
||||
* end positions (inclusive) of this span. Returns true if the position intersects, false otherwise.
|
||||
* @param position The position to check.
|
||||
*/
|
||||
public intersectsWithPosition(position: number): boolean {
|
||||
return position <= this.end() && position >= this._start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the intersection with the given span, or undefined if there is no intersection.
|
||||
* @param span The span to check.
|
||||
*/
|
||||
public intersection(span: TextSpan): TextSpan {
|
||||
var intersectStart = Math.max(this._start, span._start);
|
||||
var intersectEnd = Math.min(this.end(), span.end());
|
||||
|
||||
if (intersectStart <= intersectEnd) {
|
||||
return TextSpan.fromBounds(intersectStart, intersectEnd);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new TextSpan from the given start and end positions
|
||||
* as opposed to a position and length.
|
||||
*/
|
||||
public static fromBounds(start: number, end: number): TextSpan {
|
||||
Debug.assert(start >= 0);
|
||||
Debug.assert(end - start >= 0);
|
||||
return new TextSpan(start, end - start);
|
||||
}
|
||||
}
|
||||
|
||||
export class TextChangeRange {
|
||||
public static unchanged = new TextChangeRange(new TextSpan(0, 0), 0);
|
||||
|
||||
private _span: TextSpan;
|
||||
private _newLength: number;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of TextChangeRange.
|
||||
*/
|
||||
constructor(span: TextSpan, newLength: number) {
|
||||
Debug.assert(newLength >= 0, "newLength");
|
||||
|
||||
this._span = span;
|
||||
this._newLength = newLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* The span of text before the edit which is being changed
|
||||
*/
|
||||
public span(): TextSpan {
|
||||
return this._span;
|
||||
}
|
||||
|
||||
/**
|
||||
* Width of the span after the edit. A 0 here would represent a delete
|
||||
*/
|
||||
public newLength(): number {
|
||||
return this._newLength;
|
||||
}
|
||||
|
||||
public newSpan(): TextSpan {
|
||||
return new TextSpan(this.span().start(), this.newLength());
|
||||
}
|
||||
|
||||
public isUnchanged(): boolean {
|
||||
return this.span().isEmpty() && this.newLength() === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to merge all the changes that occurred across several versions of a script snapshot
|
||||
* into a single change. i.e. if a user keeps making successive edits to a script we will
|
||||
* have a text change from V1 to V2, V2 to V3, ..., Vn.
|
||||
*
|
||||
* This function will then merge those changes into a single change range valid between V1 and
|
||||
* Vn.
|
||||
*/
|
||||
public static collapseChangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange {
|
||||
if (changes.length === 0) {
|
||||
return TextChangeRange.unchanged;
|
||||
}
|
||||
|
||||
if (changes.length === 1) {
|
||||
return changes[0];
|
||||
}
|
||||
|
||||
// We change from talking about { { oldStart, oldLength }, newLength } to { oldStart, oldEnd, newEnd }
|
||||
// as it makes things much easier to reason about.
|
||||
var change0 = changes[0];
|
||||
|
||||
var oldStartN = change0.span().start();
|
||||
var oldEndN = change0.span().end();
|
||||
var newEndN = oldStartN + change0.newLength();
|
||||
|
||||
for (var i = 1; i < changes.length; i++) {
|
||||
var nextChange = changes[i];
|
||||
|
||||
// Consider the following case:
|
||||
// i.e. two edits. The first represents the text change range { { 10, 50 }, 30 }. i.e. The span starting
|
||||
// at 10, with length 50 is reduced to length 30. The second represents the text change range { { 30, 30 }, 40 }.
|
||||
// i.e. the span starting at 30 with length 30 is increased to length 40.
|
||||
//
|
||||
// 0 10 20 30 40 50 60 70 80 90 100
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
// | /
|
||||
// | /----
|
||||
// T1 | /----
|
||||
// | /----
|
||||
// | /----
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
// | \
|
||||
// | \
|
||||
// T2 | \
|
||||
// | \
|
||||
// | \
|
||||
// -------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// Merging these turns out to not be too difficult. First, determining the new start of the change is trivial
|
||||
// it's just the min of the old and new starts. i.e.:
|
||||
//
|
||||
// 0 10 20 30 40 50 60 70 80 90 100
|
||||
// ------------------------------------------------------------*------------------------------------------
|
||||
// | /
|
||||
// | /----
|
||||
// T1 | /----
|
||||
// | /----
|
||||
// | /----
|
||||
// ----------------------------------------$-------------------$------------------------------------------
|
||||
// . | \
|
||||
// . | \
|
||||
// T2 . | \
|
||||
// . | \
|
||||
// . | \
|
||||
// ----------------------------------------------------------------------*--------------------------------
|
||||
//
|
||||
// (Note the dots represent the newly inferrred start.
|
||||
// Determining the new and old end is also pretty simple. Basically it boils down to paying attention to the
|
||||
// absolute positions at the asterixes, and the relative change between the dollar signs. Basically, we see
|
||||
// which if the two $'s precedes the other, and we move that one forward until they line up. in this case that
|
||||
// means:
|
||||
//
|
||||
// 0 10 20 30 40 50 60 70 80 90 100
|
||||
// --------------------------------------------------------------------------------*----------------------
|
||||
// | /
|
||||
// | /----
|
||||
// T1 | /----
|
||||
// | /----
|
||||
// | /----
|
||||
// ------------------------------------------------------------$------------------------------------------
|
||||
// . | \
|
||||
// . | \
|
||||
// T2 . | \
|
||||
// . | \
|
||||
// . | \
|
||||
// ----------------------------------------------------------------------*--------------------------------
|
||||
//
|
||||
// In other words (in this case), we're recognizing that the second edit happened after where the first edit
|
||||
// ended with a delta of 20 characters (60 - 40). Thus, if we go back in time to where the first edit started
|
||||
// that's the same as if we started at char 80 instead of 60.
|
||||
//
|
||||
// As it so happens, the same logic applies if the second edit precedes the first edit. In that case rahter
|
||||
// than pusing the first edit forward to match the second, we'll push the second edit forward to match the
|
||||
// first.
|
||||
//
|
||||
// In this case that means we have { oldStart: 10, oldEnd: 80, newEnd: 70 } or, in TextChangeRange
|
||||
// semantics: { { start: 10, length: 70 }, newLength: 60 }
|
||||
//
|
||||
// The math then works out as follows.
|
||||
// If we have { oldStart1, oldEnd1, newEnd1 } and { oldStart2, oldEnd2, newEnd2 } then we can compute the
|
||||
// final result like so:
|
||||
//
|
||||
// {
|
||||
// oldStart3: Min(oldStart1, oldStart2),
|
||||
// oldEnd3 : Max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)),
|
||||
// newEnd3 : Max(newEnd2, newEnd2 + (newEnd1 - oldEnd2))
|
||||
// }
|
||||
|
||||
var oldStart1 = oldStartN;
|
||||
var oldEnd1 = oldEndN;
|
||||
var newEnd1 = newEndN;
|
||||
|
||||
var oldStart2 = nextChange.span().start();
|
||||
var oldEnd2 = nextChange.span().end();
|
||||
var newEnd2 = oldStart2 + nextChange.newLength();
|
||||
|
||||
oldStartN = Math.min(oldStart1, oldStart2);
|
||||
oldEndN = Math.max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1));
|
||||
newEndN = Math.max(newEnd2, newEnd2 + (newEnd1 - oldEnd2));
|
||||
}
|
||||
|
||||
return new TextChangeRange(TextSpan.fromBounds(oldStartN, oldEndN), /*newLength: */newEndN - oldStartN);
|
||||
}
|
||||
}
|
||||
}
|
||||
+81
-27
@@ -5,23 +5,83 @@ module ts {
|
||||
list: Node;
|
||||
}
|
||||
|
||||
export function getEndLinePosition(line: number, sourceFile: SourceFile): number {
|
||||
Debug.assert(line >= 1);
|
||||
var lineStarts = sourceFile.getLineStarts();
|
||||
|
||||
// lines returned by SourceFile.getLineAndCharacterForPosition are 1-based
|
||||
var lineIndex = line - 1;
|
||||
if (lineIndex === lineStarts.length - 1) {
|
||||
// last line - return EOF
|
||||
return sourceFile.text.length - 1;
|
||||
}
|
||||
else {
|
||||
// current line start
|
||||
var start = lineStarts[lineIndex];
|
||||
// take the start position of the next line -1 = it should be some line break
|
||||
var pos = lineStarts[lineIndex + 1] - 1;
|
||||
Debug.assert(isLineBreak(sourceFile.text.charCodeAt(pos)));
|
||||
// walk backwards skipping line breaks, stop the the beginning of current line.
|
||||
// i.e:
|
||||
// <some text>
|
||||
// $ <- end of line for this position should match the start position
|
||||
while (start <= pos && isLineBreak(sourceFile.text.charCodeAt(pos))) {
|
||||
pos--;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
export function getStartPositionOfLine(line: number, sourceFile: SourceFile): number {
|
||||
Debug.assert(line >= 1);
|
||||
return sourceFile.getLineStarts()[line - 1];
|
||||
}
|
||||
|
||||
export function getStartLinePositionForPosition(position: number, sourceFile: SourceFile): number {
|
||||
var lineStarts = sourceFile.getLineStarts();
|
||||
var line = sourceFile.getLineAndCharacterFromPosition(position).line;
|
||||
return lineStarts[line - 1];
|
||||
}
|
||||
|
||||
export function rangeContainsRange(r1: TextRange, r2: TextRange): boolean {
|
||||
return startEndContainsRange(r1.pos, r1.end, r2);
|
||||
}
|
||||
|
||||
export function startEndContainsRange(start: number, end: number, range: TextRange): boolean {
|
||||
return start <= range.pos && end >= range.end;
|
||||
}
|
||||
|
||||
export function rangeContainsStartEnd(range: TextRange, start: number, end: number): boolean {
|
||||
return range.pos <= start && range.end >= end;
|
||||
}
|
||||
|
||||
export function rangeOverlapsWithStartEnd(r1: TextRange, start: number, end: number) {
|
||||
return startEndOverlapsWithStartEnd(r1.pos, r1.end, start, end);
|
||||
}
|
||||
|
||||
export function startEndOverlapsWithStartEnd(start1: number, end1: number, start2: number, end2: number) {
|
||||
var start = Math.max(start1, start2);
|
||||
var end = Math.min(end1, end2);
|
||||
return start < end;
|
||||
}
|
||||
|
||||
export function findListItemInfo(node: Node): ListItemInfo {
|
||||
var syntaxList = findContainingList(node);
|
||||
var list = findContainingList(node);
|
||||
|
||||
// It is possible at this point for syntaxList to be undefined, either if
|
||||
// node.parent had no list child, or if none of its list children contained
|
||||
// the span of node. If this happens, return undefined. The caller should
|
||||
// handle this case.
|
||||
if (!syntaxList) {
|
||||
if (!list) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
var children = syntaxList.getChildren();
|
||||
var index = indexOf(children, node);
|
||||
var children = list.getChildren();
|
||||
var listItemIndex = indexOf(children, node);
|
||||
|
||||
return {
|
||||
listItemIndex: index,
|
||||
list: syntaxList
|
||||
listItemIndex,
|
||||
list
|
||||
};
|
||||
}
|
||||
|
||||
@@ -63,14 +123,14 @@ module ts {
|
||||
* position >= start and (position < end or (position === end && token is keyword or identifier))
|
||||
*/
|
||||
export function getTouchingWord(sourceFile: SourceFile, position: number): Node {
|
||||
return getTouchingToken(sourceFile, position, isWord);
|
||||
return getTouchingToken(sourceFile, position, n => isWord(n.kind));
|
||||
}
|
||||
|
||||
/* Gets the token whose text has range [start, end) and position >= start
|
||||
* and (position < end or (position === end && token is keyword or identifier or numeric\string litera))
|
||||
*/
|
||||
export function getTouchingPropertyName(sourceFile: SourceFile, position: number): Node {
|
||||
return getTouchingToken(sourceFile, position, isPropertyName);
|
||||
return getTouchingToken(sourceFile, position, n => isPropertyName(n.kind));
|
||||
}
|
||||
|
||||
/** Returns the token if position is in [start, end) or if position === end and includeItemAtEndPosition(token) === true */
|
||||
@@ -220,22 +280,16 @@ module ts {
|
||||
}
|
||||
|
||||
function nodeHasTokens(n: Node): boolean {
|
||||
if (n.kind === SyntaxKind.ExpressionStatement) {
|
||||
return nodeHasTokens((<ExpressionStatement>n).expression);
|
||||
}
|
||||
|
||||
if (n.kind === SyntaxKind.EndOfFileToken ||
|
||||
n.kind === SyntaxKind.OmittedExpression ||
|
||||
n.kind === SyntaxKind.Missing ||
|
||||
n.kind === SyntaxKind.Unknown) {
|
||||
if (n.kind === SyntaxKind.Unknown) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// SyntaxList is already realized so getChildCount should be fast and non-expensive
|
||||
return n.kind !== SyntaxKind.SyntaxList || n.getChildCount() !== 0;
|
||||
// If we have a token or node that has a non-zero width, it must have tokens.
|
||||
// Note, that getWidth() does not take trivia into account.
|
||||
return n.getWidth() !== 0;
|
||||
}
|
||||
|
||||
export function getTypeArgumentOrTypeParameterList(node: Node): NodeArray<Node> {
|
||||
export function getTypeArgumentOrTypeParameterList(node: Node): NodeArray<Node> {
|
||||
if (node.kind === SyntaxKind.TypeReference || node.kind === SyntaxKind.CallExpression) {
|
||||
return (<CallExpression>node).typeArguments;
|
||||
}
|
||||
@@ -251,19 +305,19 @@ module ts {
|
||||
return n.kind >= SyntaxKind.FirstToken && n.kind <= SyntaxKind.LastToken;
|
||||
}
|
||||
|
||||
function isWord(n: Node): boolean {
|
||||
return n.kind === SyntaxKind.Identifier || isKeyword(n.kind);
|
||||
function isWord(kind: SyntaxKind): boolean {
|
||||
return kind === SyntaxKind.Identifier || isKeyword(kind);
|
||||
}
|
||||
|
||||
function isPropertyName(n: Node): boolean {
|
||||
return n.kind === SyntaxKind.StringLiteral || n.kind === SyntaxKind.NumericLiteral || isWord(n);
|
||||
function isPropertyName(kind: SyntaxKind): boolean {
|
||||
return kind === SyntaxKind.StringLiteral || kind === SyntaxKind.NumericLiteral || isWord(kind);
|
||||
}
|
||||
|
||||
export function isComment(n: Node): boolean {
|
||||
return n.kind === SyntaxKind.SingleLineCommentTrivia || n.kind === SyntaxKind.MultiLineCommentTrivia;
|
||||
export function isComment(kind: SyntaxKind): boolean {
|
||||
return kind === SyntaxKind.SingleLineCommentTrivia || kind === SyntaxKind.MultiLineCommentTrivia;
|
||||
}
|
||||
|
||||
export function isPunctuation(n: Node): boolean {
|
||||
return SyntaxKind.FirstPunctuation <= n.kind && n.kind <= SyntaxKind.LastPunctuation;
|
||||
export function isPunctuation(kind: SyntaxKind): boolean {
|
||||
return SyntaxKind.FirstPunctuation <= kind && kind <= SyntaxKind.LastPunctuation;
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,7 @@ var VisualizationModel = (function (_super) {
|
||||
})(Backbone.Model);
|
||||
exports.VisualizationModel = VisualizationModel;
|
||||
//// [aliasUsageInIndexerOfClass_main.js]
|
||||
var moduleA = require("aliasUsageInIndexerOfClass_moduleA");
|
||||
var N = (function () {
|
||||
function N() {
|
||||
this.x = moduleA;
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
//// [amdModuleName1.ts]
|
||||
///<amd-module name='NamedModule'/>
|
||||
class Foo {
|
||||
x: number;
|
||||
constructor() {
|
||||
this.x = 5;
|
||||
}
|
||||
}
|
||||
export = Foo;
|
||||
|
||||
|
||||
//// [amdModuleName1.js]
|
||||
define("NamedModule", ["require", "exports"], function (require, exports) {
|
||||
///<amd-module name='NamedModule'/>
|
||||
var Foo = (function () {
|
||||
function Foo() {
|
||||
this.x = 5;
|
||||
}
|
||||
return Foo;
|
||||
})();
|
||||
return Foo;
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
=== tests/cases/compiler/amdModuleName1.ts ===
|
||||
///<amd-module name='NamedModule'/>
|
||||
class Foo {
|
||||
>Foo : Foo
|
||||
|
||||
x: number;
|
||||
>x : number
|
||||
|
||||
constructor() {
|
||||
this.x = 5;
|
||||
>this.x = 5 : number
|
||||
>this.x : number
|
||||
>this : Foo
|
||||
>x : number
|
||||
}
|
||||
}
|
||||
export = Foo;
|
||||
>Foo : Foo
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
tests/cases/compiler/amdModuleName2.ts(2,1): error TS2458: An AMD module cannot have multiple name assignments.
|
||||
|
||||
|
||||
==== tests/cases/compiler/amdModuleName2.ts (1 errors) ====
|
||||
///<amd-module name='FirstModuleName'/>
|
||||
///<amd-module name='SecondModuleName'/>
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2458: An AMD module cannot have multiple name assignments.
|
||||
class Foo {
|
||||
x: number;
|
||||
constructor() {
|
||||
this.x = 5;
|
||||
}
|
||||
}
|
||||
export = Foo;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
//// [tests/cases/compiler/elidingImportNames.ts] ////
|
||||
|
||||
//// [elidingImportNames_test.ts]
|
||||
|
||||
import a = require('elidingImportNames_main'); // alias used in typeof
|
||||
var b = a;
|
||||
var x: typeof a;
|
||||
import a2 = require('elidingImportNames_main1'); // alias not used in typeof
|
||||
var b2 = a2;
|
||||
|
||||
|
||||
//// [elidingImportNames_main.ts]
|
||||
export var main = 10;
|
||||
|
||||
//// [elidingImportNames_main1.ts]
|
||||
export var main = 10;
|
||||
|
||||
//// [elidingImportNames_main.js]
|
||||
exports.main = 10;
|
||||
//// [elidingImportNames_main1.js]
|
||||
exports.main = 10;
|
||||
//// [elidingImportNames_test.js]
|
||||
var a = require('elidingImportNames_main'); // alias used in typeof
|
||||
var b = a;
|
||||
var x;
|
||||
var a2 = require('elidingImportNames_main1'); // alias not used in typeof
|
||||
var b2 = a2;
|
||||
@@ -0,0 +1,29 @@
|
||||
=== tests/cases/compiler/elidingImportNames_test.ts ===
|
||||
|
||||
import a = require('elidingImportNames_main'); // alias used in typeof
|
||||
>a : typeof a
|
||||
|
||||
var b = a;
|
||||
>b : typeof a
|
||||
>a : typeof a
|
||||
|
||||
var x: typeof a;
|
||||
>x : typeof a
|
||||
>a : typeof a
|
||||
|
||||
import a2 = require('elidingImportNames_main1'); // alias not used in typeof
|
||||
>a2 : typeof a2
|
||||
|
||||
var b2 = a2;
|
||||
>b2 : typeof a2
|
||||
>a2 : typeof a2
|
||||
|
||||
|
||||
=== tests/cases/compiler/elidingImportNames_main.ts ===
|
||||
export var main = 10;
|
||||
>main : number
|
||||
|
||||
=== tests/cases/compiler/elidingImportNames_main1.ts ===
|
||||
export var main = 10;
|
||||
>main : number
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
tests/cases/compiler/incompleteObjectLiteral1.ts(1,14): error TS1005: ':' expected.
|
||||
tests/cases/compiler/incompleteObjectLiteral1.ts(1,14): error TS1005: ',' expected.
|
||||
tests/cases/compiler/incompleteObjectLiteral1.ts(1,16): error TS1128: Declaration or statement expected.
|
||||
tests/cases/compiler/incompleteObjectLiteral1.ts(1,12): error TS2304: Cannot find name 'aa'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/incompleteObjectLiteral1.ts (2 errors) ====
|
||||
==== tests/cases/compiler/incompleteObjectLiteral1.ts (3 errors) ====
|
||||
var tt = { aa; }
|
||||
~
|
||||
!!! error TS1005: ':' expected.
|
||||
!!! error TS1005: ',' expected.
|
||||
~
|
||||
!!! error TS1128: Declaration or statement expected.
|
||||
~~
|
||||
!!! error TS2304: Cannot find name 'aa'.
|
||||
var x = tt;
|
||||
@@ -1,12 +1,10 @@
|
||||
error TS2318: Cannot find global type 'Boolean'.
|
||||
error TS2318: Cannot find global type 'IArguments'.
|
||||
error TS2318: Cannot find global type 'TemplateStringsArray'.
|
||||
tests/cases/compiler/noDefaultLib.ts(4,11): error TS2317: Global type 'Array' must have 1 type parameter(s).
|
||||
|
||||
|
||||
!!! error TS2318: Cannot find global type 'Boolean'.
|
||||
!!! error TS2318: Cannot find global type 'IArguments'.
|
||||
!!! error TS2318: Cannot find global type 'TemplateStringsArray'.
|
||||
==== tests/cases/compiler/noDefaultLib.ts (1 errors) ====
|
||||
/// <reference no-default-lib="true"/>
|
||||
var x;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
tests/cases/compiler/noEmitOnError.ts(2,5): error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
|
||||
|
||||
==== tests/cases/compiler/noEmitOnError.ts (1 errors) ====
|
||||
|
||||
var x: number = "";
|
||||
~
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
//// [objectLiteralShorthandProperties.ts]
|
||||
var a, b, c;
|
||||
|
||||
var x1 = {
|
||||
a
|
||||
};
|
||||
|
||||
var x2 = {
|
||||
a,
|
||||
}
|
||||
|
||||
var x3 = {
|
||||
a: 0,
|
||||
b,
|
||||
c,
|
||||
d() { },
|
||||
x3,
|
||||
parent: x3
|
||||
};
|
||||
|
||||
|
||||
|
||||
//// [objectLiteralShorthandProperties.js]
|
||||
var a, b, c;
|
||||
var x1 = {
|
||||
a: a
|
||||
};
|
||||
var x2 = {
|
||||
a: a,
|
||||
};
|
||||
var x3 = {
|
||||
a: 0,
|
||||
b: b,
|
||||
c: c,
|
||||
d: function () {
|
||||
},
|
||||
x3: x3,
|
||||
parent: x3
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
=== tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandProperties.ts ===
|
||||
var a, b, c;
|
||||
>a : any
|
||||
>b : any
|
||||
>c : any
|
||||
|
||||
var x1 = {
|
||||
>x1 : { a: any; }
|
||||
>{ a} : { a: any; }
|
||||
|
||||
a
|
||||
>a : any
|
||||
|
||||
};
|
||||
|
||||
var x2 = {
|
||||
>x2 : { a: any; }
|
||||
>{ a,} : { a: any; }
|
||||
|
||||
a,
|
||||
>a : any
|
||||
}
|
||||
|
||||
var x3 = {
|
||||
>x3 : any
|
||||
>{ a: 0, b, c, d() { }, x3, parent: x3} : { a: number; b: any; c: any; d: () => void; x3: any; parent: any; }
|
||||
|
||||
a: 0,
|
||||
>a : number
|
||||
|
||||
b,
|
||||
>b : any
|
||||
|
||||
c,
|
||||
>c : any
|
||||
|
||||
d() { },
|
||||
>d : () => void
|
||||
>d() { } : () => void
|
||||
|
||||
x3,
|
||||
>x3 : any
|
||||
|
||||
parent: x3
|
||||
>parent : any
|
||||
>x3 : any
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
//// [objectLiteralShorthandPropertiesAssignment.ts]
|
||||
var id: number = 10000;
|
||||
var name: string = "my name";
|
||||
|
||||
var person: { name: string; id: number } = { name, id };
|
||||
function foo( obj:{ name: string }): void { };
|
||||
function bar(name: string, id: number) { return { name, id }; }
|
||||
function bar1(name: string, id: number) { return { name }; }
|
||||
function baz(name: string, id: number): { name: string; id: number } { return { name, id }; }
|
||||
|
||||
foo(person);
|
||||
var person1 = bar("Hello", 5);
|
||||
var person2: { name: string } = bar("Hello", 5);
|
||||
var person3: { name: string; id:number } = bar("Hello", 5);
|
||||
|
||||
|
||||
//// [objectLiteralShorthandPropertiesAssignment.js]
|
||||
var id = 10000;
|
||||
var name = "my name";
|
||||
var person = { name: name, id: id };
|
||||
function foo(obj) {
|
||||
}
|
||||
;
|
||||
function bar(name, id) {
|
||||
return { name: name, id: id };
|
||||
}
|
||||
function bar1(name, id) {
|
||||
return { name: name };
|
||||
}
|
||||
function baz(name, id) {
|
||||
return { name: name, id: id };
|
||||
}
|
||||
foo(person);
|
||||
var person1 = bar("Hello", 5);
|
||||
var person2 = bar("Hello", 5);
|
||||
var person3 = bar("Hello", 5);
|
||||
@@ -0,0 +1,68 @@
|
||||
=== tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignment.ts ===
|
||||
var id: number = 10000;
|
||||
>id : number
|
||||
|
||||
var name: string = "my name";
|
||||
>name : string
|
||||
|
||||
var person: { name: string; id: number } = { name, id };
|
||||
>person : { name: string; id: number; }
|
||||
>name : string
|
||||
>id : number
|
||||
>{ name, id } : { name: string; id: number; }
|
||||
>name : string
|
||||
>id : number
|
||||
|
||||
function foo( obj:{ name: string }): void { };
|
||||
>foo : (obj: { name: string; }) => void
|
||||
>obj : { name: string; }
|
||||
>name : string
|
||||
|
||||
function bar(name: string, id: number) { return { name, id }; }
|
||||
>bar : (name: string, id: number) => { name: string; id: number; }
|
||||
>name : string
|
||||
>id : number
|
||||
>{ name, id } : { name: string; id: number; }
|
||||
>name : string
|
||||
>id : number
|
||||
|
||||
function bar1(name: string, id: number) { return { name }; }
|
||||
>bar1 : (name: string, id: number) => { name: string; }
|
||||
>name : string
|
||||
>id : number
|
||||
>{ name } : { name: string; }
|
||||
>name : string
|
||||
|
||||
function baz(name: string, id: number): { name: string; id: number } { return { name, id }; }
|
||||
>baz : (name: string, id: number) => { name: string; id: number; }
|
||||
>name : string
|
||||
>id : number
|
||||
>name : string
|
||||
>id : number
|
||||
>{ name, id } : { name: string; id: number; }
|
||||
>name : string
|
||||
>id : number
|
||||
|
||||
foo(person);
|
||||
>foo(person) : void
|
||||
>foo : (obj: { name: string; }) => void
|
||||
>person : { name: string; id: number; }
|
||||
|
||||
var person1 = bar("Hello", 5);
|
||||
>person1 : { name: string; id: number; }
|
||||
>bar("Hello", 5) : { name: string; id: number; }
|
||||
>bar : (name: string, id: number) => { name: string; id: number; }
|
||||
|
||||
var person2: { name: string } = bar("Hello", 5);
|
||||
>person2 : { name: string; }
|
||||
>name : string
|
||||
>bar("Hello", 5) : { name: string; id: number; }
|
||||
>bar : (name: string, id: number) => { name: string; id: number; }
|
||||
|
||||
var person3: { name: string; id:number } = bar("Hello", 5);
|
||||
>person3 : { name: string; id: number; }
|
||||
>name : string
|
||||
>id : number
|
||||
>bar("Hello", 5) : { name: string; id: number; }
|
||||
>bar : (name: string, id: number) => { name: string; id: number; }
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
//// [objectLiteralShorthandPropertiesAssignmentES6.ts]
|
||||
var id: number = 10000;
|
||||
var name: string = "my name";
|
||||
|
||||
var person: { name: string; id: number } = { name, id };
|
||||
function foo(obj: { name: string }): void { };
|
||||
function bar(name: string, id: number) { return { name, id }; }
|
||||
function bar1(name: string, id: number) { return { name }; }
|
||||
function baz(name: string, id: number): { name: string; id: number } { return { name, id }; }
|
||||
|
||||
foo(person);
|
||||
var person1 = bar("Hello", 5);
|
||||
var person2: { name: string } = bar("Hello", 5);
|
||||
var person3: { name: string; id: number } = bar("Hello", 5);
|
||||
|
||||
|
||||
//// [objectLiteralShorthandPropertiesAssignmentES6.js]
|
||||
var id = 10000;
|
||||
var name = "my name";
|
||||
var person = { name, id };
|
||||
function foo(obj) {
|
||||
}
|
||||
;
|
||||
function bar(name, id) {
|
||||
return { name, id };
|
||||
}
|
||||
function bar1(name, id) {
|
||||
return { name };
|
||||
}
|
||||
function baz(name, id) {
|
||||
return { name, id };
|
||||
}
|
||||
foo(person);
|
||||
var person1 = bar("Hello", 5);
|
||||
var person2 = bar("Hello", 5);
|
||||
var person3 = bar("Hello", 5);
|
||||
@@ -0,0 +1,68 @@
|
||||
=== tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignmentES6.ts ===
|
||||
var id: number = 10000;
|
||||
>id : number
|
||||
|
||||
var name: string = "my name";
|
||||
>name : string
|
||||
|
||||
var person: { name: string; id: number } = { name, id };
|
||||
>person : { name: string; id: number; }
|
||||
>name : string
|
||||
>id : number
|
||||
>{ name, id } : { name: string; id: number; }
|
||||
>name : string
|
||||
>id : number
|
||||
|
||||
function foo(obj: { name: string }): void { };
|
||||
>foo : (obj: { name: string; }) => void
|
||||
>obj : { name: string; }
|
||||
>name : string
|
||||
|
||||
function bar(name: string, id: number) { return { name, id }; }
|
||||
>bar : (name: string, id: number) => { name: string; id: number; }
|
||||
>name : string
|
||||
>id : number
|
||||
>{ name, id } : { name: string; id: number; }
|
||||
>name : string
|
||||
>id : number
|
||||
|
||||
function bar1(name: string, id: number) { return { name }; }
|
||||
>bar1 : (name: string, id: number) => { name: string; }
|
||||
>name : string
|
||||
>id : number
|
||||
>{ name } : { name: string; }
|
||||
>name : string
|
||||
|
||||
function baz(name: string, id: number): { name: string; id: number } { return { name, id }; }
|
||||
>baz : (name: string, id: number) => { name: string; id: number; }
|
||||
>name : string
|
||||
>id : number
|
||||
>name : string
|
||||
>id : number
|
||||
>{ name, id } : { name: string; id: number; }
|
||||
>name : string
|
||||
>id : number
|
||||
|
||||
foo(person);
|
||||
>foo(person) : void
|
||||
>foo : (obj: { name: string; }) => void
|
||||
>person : { name: string; id: number; }
|
||||
|
||||
var person1 = bar("Hello", 5);
|
||||
>person1 : { name: string; id: number; }
|
||||
>bar("Hello", 5) : { name: string; id: number; }
|
||||
>bar : (name: string, id: number) => { name: string; id: number; }
|
||||
|
||||
var person2: { name: string } = bar("Hello", 5);
|
||||
>person2 : { name: string; }
|
||||
>name : string
|
||||
>bar("Hello", 5) : { name: string; id: number; }
|
||||
>bar : (name: string, id: number) => { name: string; id: number; }
|
||||
|
||||
var person3: { name: string; id: number } = bar("Hello", 5);
|
||||
>person3 : { name: string; id: number; }
|
||||
>name : string
|
||||
>id : number
|
||||
>bar("Hello", 5) : { name: string; id: number; }
|
||||
>bar : (name: string, id: number) => { name: string; id: number; }
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignmentError.ts(5,16): error TS1131: Property or signature expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignmentError.ts(5,25): error TS1128: Declaration or statement expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignmentError.ts(6,53): error TS1005: ';' expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignmentError.ts(4,5): error TS2322: Type '{ name: string; id: number; }' is not assignable to type '{ b: string; id: number; }'.
|
||||
Property 'b' is missing in type '{ name: string; id: number; }'.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignmentError.ts(5,22): error TS2403: Subsequent variable declarations must have the same type. Variable 'id' must be of type 'number', but here has type 'any'.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignmentError.ts(6,79): error TS2322: Type '{ name: string; id: number; }' is not assignable to type '{ id: string; name: number; }'.
|
||||
Types of property 'id' are incompatible.
|
||||
Type 'number' is not assignable to type 'string'.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignmentError.ts(8,5): error TS2345: Argument of type '{ name: string; id: number; }' is not assignable to parameter of type '{ name: string; id: boolean; }'.
|
||||
Types of property 'id' are incompatible.
|
||||
Type 'number' is not assignable to type 'boolean'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignmentError.ts (7 errors) ====
|
||||
var id: number = 10000;
|
||||
var name: string = "my name";
|
||||
|
||||
var person: { b: string; id: number } = { name, id }; // error
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '{ name: string; id: number; }' is not assignable to type '{ b: string; id: number; }'.
|
||||
!!! error TS2322: Property 'b' is missing in type '{ name: string; id: number; }'.
|
||||
var person1: { name, id }; // error: can't use short-hand property assignment in type position
|
||||
~~~~
|
||||
!!! error TS1131: Property or signature expected.
|
||||
~
|
||||
!!! error TS1128: Declaration or statement expected.
|
||||
~~
|
||||
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'id' must be of type 'number', but here has type 'any'.
|
||||
function foo(name: string, id: number): { id: string, name: number } { return { name, id }; } // error
|
||||
~
|
||||
!!! error TS1005: ';' expected.
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS2322: Type '{ name: string; id: number; }' is not assignable to type '{ id: string; name: number; }'.
|
||||
!!! error TS2322: Types of property 'id' are incompatible.
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
function bar(obj: { name: string; id: boolean }) { }
|
||||
bar({ name, id }); // error
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS2345: Argument of type '{ name: string; id: number; }' is not assignable to parameter of type '{ name: string; id: boolean; }'.
|
||||
!!! error TS2345: Types of property 'id' are incompatible.
|
||||
!!! error TS2345: Type 'number' is not assignable to type 'boolean'.
|
||||
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignmentErrorFromMissingIdentifier.ts(5,55): error TS1005: ';' expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignmentErrorFromMissingIdentifier.ts(6,55): error TS1005: ';' expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignmentErrorFromMissingIdentifier.ts(7,16): error TS1131: Property or signature expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignmentErrorFromMissingIdentifier.ts(7,25): error TS1128: Declaration or statement expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignmentErrorFromMissingIdentifier.ts(8,28): error TS1005: ';' expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignmentErrorFromMissingIdentifier.ts(4,5): error TS2322: Type '{ name: string; id: number; }' is not assignable to type '{ b: string; id: number; }'.
|
||||
Property 'b' is missing in type '{ name: string; id: number; }'.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignmentErrorFromMissingIdentifier.ts(5,79): error TS2322: Type '{ name: string; id: number; }' is not assignable to type '{ name: number; id: string; }'.
|
||||
Types of property 'name' are incompatible.
|
||||
Type 'string' is not assignable to type 'number'.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignmentErrorFromMissingIdentifier.ts(7,22): error TS2403: Subsequent variable declarations must have the same type. Variable 'id' must be of type 'number', but here has type 'any'.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignmentErrorFromMissingIdentifier.ts(8,5): error TS2322: Type '{ name: number; id: string; }' is not assignable to type '{ name: string; id: number; }'.
|
||||
Types of property 'name' are incompatible.
|
||||
Type 'number' is not assignable to type 'string'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesAssignmentErrorFromMissingIdentifier.ts (9 errors) ====
|
||||
var id: number = 10000;
|
||||
var name: string = "my name";
|
||||
|
||||
var person: { b: string; id: number } = { name, id }; // error
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '{ name: string; id: number; }' is not assignable to type '{ b: string; id: number; }'.
|
||||
!!! error TS2322: Property 'b' is missing in type '{ name: string; id: number; }'.
|
||||
function bar(name: string, id: number): { name: number, id: string } { return { name, id }; } // error
|
||||
~
|
||||
!!! error TS1005: ';' expected.
|
||||
~~~~~~~~~~~~
|
||||
!!! error TS2322: Type '{ name: string; id: number; }' is not assignable to type '{ name: number; id: string; }'.
|
||||
!!! error TS2322: Types of property 'name' are incompatible.
|
||||
!!! error TS2322: Type 'string' is not assignable to type 'number'.
|
||||
function foo(name: string, id: number): { name: string, id: number } { return { name, id }; } // error
|
||||
~
|
||||
!!! error TS1005: ';' expected.
|
||||
var person1: { name, id }; // error : Can't use shorthand in the type position
|
||||
~~~~
|
||||
!!! error TS1131: Property or signature expected.
|
||||
~
|
||||
!!! error TS1128: Declaration or statement expected.
|
||||
~~
|
||||
!!! error TS2403: Subsequent variable declarations must have the same type. Variable 'id' must be of type 'number', but here has type 'any'.
|
||||
var person2: { name: string, id: number } = bar("hello", 5);
|
||||
~
|
||||
!!! error TS1005: ';' expected.
|
||||
~~~~~~~
|
||||
!!! error TS2322: Type '{ name: number; id: string; }' is not assignable to type '{ name: string; id: number; }'.
|
||||
!!! error TS2322: Types of property 'name' are incompatible.
|
||||
!!! error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
@@ -0,0 +1,39 @@
|
||||
//// [objectLiteralShorthandPropertiesES6.ts]
|
||||
var a, b, c;
|
||||
|
||||
var x1 = {
|
||||
a
|
||||
};
|
||||
|
||||
var x2 = {
|
||||
a,
|
||||
}
|
||||
|
||||
var x3 = {
|
||||
a: 0,
|
||||
b,
|
||||
c,
|
||||
d() { },
|
||||
x3,
|
||||
parent: x3
|
||||
};
|
||||
|
||||
|
||||
|
||||
//// [objectLiteralShorthandPropertiesES6.js]
|
||||
var a, b, c;
|
||||
var x1 = {
|
||||
a
|
||||
};
|
||||
var x2 = {
|
||||
a,
|
||||
};
|
||||
var x3 = {
|
||||
a: 0,
|
||||
b,
|
||||
c,
|
||||
d: function () {
|
||||
},
|
||||
x3,
|
||||
parent: x3
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
=== tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesES6.ts ===
|
||||
var a, b, c;
|
||||
>a : any
|
||||
>b : any
|
||||
>c : any
|
||||
|
||||
var x1 = {
|
||||
>x1 : { a: any; }
|
||||
>{ a} : { a: any; }
|
||||
|
||||
a
|
||||
>a : any
|
||||
|
||||
};
|
||||
|
||||
var x2 = {
|
||||
>x2 : { a: any; }
|
||||
>{ a,} : { a: any; }
|
||||
|
||||
a,
|
||||
>a : any
|
||||
}
|
||||
|
||||
var x3 = {
|
||||
>x3 : any
|
||||
>{ a: 0, b, c, d() { }, x3, parent: x3} : { a: number; b: any; c: any; d: () => void; x3: any; parent: any; }
|
||||
|
||||
a: 0,
|
||||
>a : number
|
||||
|
||||
b,
|
||||
>b : any
|
||||
|
||||
c,
|
||||
>c : any
|
||||
|
||||
d() { },
|
||||
>d : () => void
|
||||
>d() { } : () => void
|
||||
|
||||
x3,
|
||||
>x3 : any
|
||||
|
||||
parent: x3
|
||||
>parent : any
|
||||
>x3 : any
|
||||
|
||||
};
|
||||
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNoneExistingIdentifier.ts(3,5): error TS2304: Cannot find name 'undefinedVariable'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNoneExistingIdentifier.ts (1 errors) ====
|
||||
var x = {
|
||||
x, // OK
|
||||
undefinedVariable // Error
|
||||
~~~~~~~~~~~~~~~~~
|
||||
!!! error TS2304: Cannot find name 'undefinedVariable'.
|
||||
}
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
//// [objectLiteralShorthandPropertiesErrorFromNoneExistingIdentifier.ts]
|
||||
var x = {
|
||||
x, // OK
|
||||
undefinedVariable // Error
|
||||
}
|
||||
|
||||
|
||||
//// [objectLiteralShorthandPropertiesErrorFromNoneExistingIdentifier.js]
|
||||
var x = {
|
||||
x: x,
|
||||
undefinedVariable: undefinedVariable // Error
|
||||
};
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(3,20): error TS1005: ':' expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(4,7): error TS1005: ':' expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(5,10): error TS1005: '(' expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(6,10): error TS1005: '(' expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(7,9): error TS1005: ':' expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(8,10): error TS1005: ':' expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(9,8): error TS1005: ':' expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(10,10): error TS1005: ':' expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(12,1): error TS1005: ':' expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(15,6): error TS1005: ',' expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(16,6): error TS1005: ',' expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(17,6): error TS1005: '=' expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(18,1): error TS1128: Declaration or statement expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(20,17): error TS1005: ':' expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(5,9): error TS2378: A 'get' accessor must return a value or consist of a single 'throw' statement.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(15,5): error TS2300: Duplicate identifier 'a'.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(15,7): error TS2304: Cannot find name 'b'.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts(16,5): error TS2300: Duplicate identifier 'a'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorFromNotUsingIdentifier.ts (18 errors) ====
|
||||
// errors
|
||||
var y = {
|
||||
"stringLiteral",
|
||||
~
|
||||
!!! error TS1005: ':' expected.
|
||||
42,
|
||||
~
|
||||
!!! error TS1005: ':' expected.
|
||||
get e,
|
||||
~
|
||||
!!! error TS1005: '(' expected.
|
||||
~
|
||||
!!! error TS2378: A 'get' accessor must return a value or consist of a single 'throw' statement.
|
||||
set f,
|
||||
~
|
||||
!!! error TS1005: '(' expected.
|
||||
this,
|
||||
~
|
||||
!!! error TS1005: ':' expected.
|
||||
super,
|
||||
~
|
||||
!!! error TS1005: ':' expected.
|
||||
var,
|
||||
~
|
||||
!!! error TS1005: ':' expected.
|
||||
class,
|
||||
~
|
||||
!!! error TS1005: ':' expected.
|
||||
typeof
|
||||
};
|
||||
~
|
||||
!!! error TS1005: ':' expected.
|
||||
|
||||
var x = {
|
||||
a.b,
|
||||
~
|
||||
!!! error TS1005: ',' expected.
|
||||
~
|
||||
!!! error TS2300: Duplicate identifier 'a'.
|
||||
~
|
||||
!!! error TS2304: Cannot find name 'b'.
|
||||
a["ss"],
|
||||
~
|
||||
!!! error TS1005: ',' expected.
|
||||
~
|
||||
!!! error TS2300: Duplicate identifier 'a'.
|
||||
a[1],
|
||||
~
|
||||
!!! error TS1005: '=' expected.
|
||||
};
|
||||
~
|
||||
!!! error TS1128: Declaration or statement expected.
|
||||
|
||||
var v = { class }; // error
|
||||
~
|
||||
!!! error TS1005: ':' expected.
|
||||
@@ -0,0 +1,24 @@
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorWithModule.ts(10,10): error TS1005: ',' expected.
|
||||
tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorWithModule.ts(14,3): error TS2339: Property 'y' does not exist on type 'typeof m'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/es6/shorthandPropertyAssignment/objectLiteralShorthandPropertiesErrorWithModule.ts (2 errors) ====
|
||||
// module export
|
||||
var x = "Foo";
|
||||
module m {
|
||||
export var x;
|
||||
}
|
||||
|
||||
module n {
|
||||
var z = 10000;
|
||||
export var y = {
|
||||
m.x // error
|
||||
~
|
||||
!!! error TS1005: ',' expected.
|
||||
};
|
||||
}
|
||||
|
||||
m.y.x;
|
||||
~
|
||||
!!! error TS2339: Property 'y' does not exist on type 'typeof m'.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user