Merge branch 'master' into relativePathReferenceResolution

This commit is contained in:
Sheetal Nandi
2014-11-19 13:11:17 -08:00
262 changed files with 22510 additions and 22551 deletions
+4
View File
@@ -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;
+4
View File
@@ -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
View File
File diff suppressed because one or more lines are too long
+5141 -17281
View File
File diff suppressed because one or more lines are too long
+46 -9
View File
@@ -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
View File
@@ -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();
+8 -3
View File
@@ -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[]) {
+9 -9
View File
@@ -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'" },
+21
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+12 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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) {
+23 -23
View File
@@ -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 */
+12 -12
View File
@@ -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 {
+3 -3
View File
@@ -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 };
}
});
+3 -3
View File
@@ -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
View File
@@ -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));
+953
View File
@@ -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;
}
}
-315
View File
@@ -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;
}
}
}
}
+46 -47
View File
@@ -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);
}
}
}
+54
View File
@@ -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' />
+2 -2
View File
@@ -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,
+7 -7
View File
@@ -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
}
}
+2 -3
View File
@@ -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);
}
+3 -3
View File
@@ -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
}
+2 -2
View File
@@ -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; }[];
+74 -39
View File
@@ -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;
}
}
}
+2 -2
View File
@@ -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;
+3 -3
View File
@@ -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();
}
-30
View File
@@ -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);
}
}
}
-28
View File
@@ -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 + "' ]";
}
}
}
-89
View File
@@ -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));
}
}
}
+11 -21
View File
@@ -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]);
}
}
}
+2 -3
View File
@@ -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);
-49
View File
@@ -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;
}
}
+9 -10
View File
@@ -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 {
+5 -5
View File
@@ -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 },
+13 -1
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+10 -28
View File
@@ -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");
}
}
}
+22 -22
View File
@@ -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;
}
+58 -43
View File
@@ -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
+10 -8
View File
@@ -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
}
}
File diff suppressed because it is too large Load Diff
+6
View File
@@ -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);
+10 -12
View File
@@ -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 {
+28 -10
View File
@@ -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 {
+32 -20
View File
@@ -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;
+1
View File
@@ -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;
}
}
+16 -7
View File
@@ -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);
+296
View File
@@ -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
View File
@@ -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'.
@@ -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
};
@@ -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'.
}
@@ -0,0 +1,12 @@
//// [objectLiteralShorthandPropertiesErrorFromNoneExistingIdentifier.ts]
var x = {
x, // OK
undefinedVariable // Error
}
//// [objectLiteralShorthandPropertiesErrorFromNoneExistingIdentifier.js]
var x = {
x: x,
undefinedVariable: undefinedVariable // Error
};
@@ -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