mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' of https://github.com/Microsoft/TypeScript into esSymbols
Conflicts: src/compiler/diagnosticInformationMap.generated.ts
This commit is contained in:
+160
-134
@@ -5922,10 +5922,74 @@ module ts {
|
||||
return unknownSignature;
|
||||
}
|
||||
|
||||
// Re-order candidate signatures into the result array. Assumes the result array to be empty.
|
||||
// The candidate list orders groups in reverse, but within a group signatures are kept in declaration order
|
||||
// A nit here is that we reorder only signatures that belong to the same symbol,
|
||||
// so order how inherited signatures are processed is still preserved.
|
||||
// interface A { (x: string): void }
|
||||
// interface B extends A { (x: 'foo'): string }
|
||||
// var b: B;
|
||||
// b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void]
|
||||
function reorderCandidates(signatures: Signature[], result: Signature[]): void {
|
||||
var lastParent: Node;
|
||||
var lastSymbol: Symbol;
|
||||
var cutoffIndex: number = 0;
|
||||
var index: number;
|
||||
var specializedIndex: number = -1;
|
||||
var spliceIndex: number;
|
||||
Debug.assert(!result.length);
|
||||
for (var i = 0; i < signatures.length; i++) {
|
||||
var signature = signatures[i];
|
||||
var symbol = signature.declaration && getSymbolOfNode(signature.declaration);
|
||||
var parent = signature.declaration && signature.declaration.parent;
|
||||
if (!lastSymbol || symbol === lastSymbol) {
|
||||
if (lastParent && parent === lastParent) {
|
||||
index++;
|
||||
}
|
||||
else {
|
||||
lastParent = parent;
|
||||
index = cutoffIndex;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// current declaration belongs to a different symbol
|
||||
// set cutoffIndex so re-orderings in the future won't change result set from 0 to cutoffIndex
|
||||
index = cutoffIndex = result.length;
|
||||
lastParent = parent;
|
||||
}
|
||||
lastSymbol = symbol;
|
||||
|
||||
// specialized signatures always need to be placed before non-specialized signatures regardless
|
||||
// of the cutoff position; see GH#1133
|
||||
if (signature.hasStringLiterals) {
|
||||
specializedIndex++;
|
||||
spliceIndex = specializedIndex;
|
||||
// The cutoff index always needs to be greater than or equal to the specialized signature index
|
||||
// in order to prevent non-specialized signatures from being added before a specialized
|
||||
// signature.
|
||||
cutoffIndex++;
|
||||
}
|
||||
else {
|
||||
spliceIndex = index;
|
||||
}
|
||||
|
||||
result.splice(spliceIndex, 0, signature);
|
||||
}
|
||||
}
|
||||
|
||||
function getSpreadArgumentIndex(args: Expression[]): number {
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
if (args[i].kind === SyntaxKind.SpreadElementExpression) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function hasCorrectArity(node: CallLikeExpression, args: Expression[], signature: Signature) {
|
||||
var adjustedArgCount: number;
|
||||
var typeArguments: NodeArray<TypeNode>;
|
||||
var callIsIncomplete: boolean;
|
||||
var adjustedArgCount: number; // Apparent number of arguments we will have in this call
|
||||
var typeArguments: NodeArray<TypeNode>; // Type arguments (undefined if none)
|
||||
var callIsIncomplete: boolean; // In incomplete call we want to be lenient when we have too few arguments
|
||||
|
||||
if (node.kind === SyntaxKind.TaggedTemplateExpression) {
|
||||
var tagExpression = <TaggedTemplateExpression>node;
|
||||
@@ -5970,35 +6034,29 @@ module ts {
|
||||
typeArguments = callExpression.typeArguments;
|
||||
}
|
||||
|
||||
Debug.assert(adjustedArgCount !== undefined, "'adjustedArgCount' undefined");
|
||||
Debug.assert(callIsIncomplete !== undefined, "'callIsIncomplete' undefined");
|
||||
|
||||
return checkArity(adjustedArgCount, typeArguments, callIsIncomplete, signature);
|
||||
|
||||
/**
|
||||
* @param adjustedArgCount The "apparent" number of arguments that we will have in this call.
|
||||
* @param typeArguments Type arguments node of the call if it exists; undefined otherwise.
|
||||
* @param callIsIncomplete Whether or not a call is unfinished, and we should be "lenient" when we have too few arguments.
|
||||
* @param signature The signature whose arity we are comparing.
|
||||
*/
|
||||
function checkArity(adjustedArgCount: number, typeArguments: NodeArray<TypeNode>, callIsIncomplete: boolean, signature: Signature): boolean {
|
||||
// Too many arguments implies incorrect arity.
|
||||
if (!signature.hasRestParameter && adjustedArgCount > signature.parameters.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the user supplied type arguments, but the number of type arguments does not match
|
||||
// the declared number of type parameters, the call has an incorrect arity.
|
||||
var hasRightNumberOfTypeArgs = !typeArguments ||
|
||||
(signature.typeParameters && typeArguments.length === signature.typeParameters.length);
|
||||
if (!hasRightNumberOfTypeArgs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the call is incomplete, we should skip the lower bound check.
|
||||
var hasEnoughArguments = adjustedArgCount >= signature.minArgumentCount;
|
||||
return callIsIncomplete || hasEnoughArguments;
|
||||
// If the user supplied type arguments, but the number of type arguments does not match
|
||||
// the declared number of type parameters, the call has an incorrect arity.
|
||||
var hasRightNumberOfTypeArgs = !typeArguments ||
|
||||
(signature.typeParameters && typeArguments.length === signature.typeParameters.length);
|
||||
if (!hasRightNumberOfTypeArgs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If spread arguments are present, check that they correspond to a rest parameter. If so, no
|
||||
// further checking is necessary.
|
||||
var spreadArgIndex = getSpreadArgumentIndex(args);
|
||||
if (spreadArgIndex >= 0) {
|
||||
return signature.hasRestParameter && spreadArgIndex >= signature.parameters.length - 1;
|
||||
}
|
||||
|
||||
// Too many arguments implies incorrect arity.
|
||||
if (!signature.hasRestParameter && adjustedArgCount > signature.parameters.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the call is incomplete, we should skip the lower bound check.
|
||||
var hasEnoughArguments = adjustedArgCount >= signature.minArgumentCount;
|
||||
return callIsIncomplete || hasEnoughArguments;
|
||||
}
|
||||
|
||||
// If type has a single call signature and no other members, return that signature. Otherwise, return undefined.
|
||||
@@ -6031,18 +6089,20 @@ module ts {
|
||||
// We perform two passes over the arguments. In the first pass we infer from all arguments, but use
|
||||
// wildcards for all context sensitive function expressions.
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
if (args[i].kind === SyntaxKind.OmittedExpression) {
|
||||
continue;
|
||||
var arg = args[i];
|
||||
if (arg.kind !== SyntaxKind.OmittedExpression) {
|
||||
var paramType = getTypeAtPosition(signature, arg.kind === SyntaxKind.SpreadElementExpression ? -1 : i);
|
||||
if (i === 0 && args[i].parent.kind === SyntaxKind.TaggedTemplateExpression) {
|
||||
var argType = globalTemplateStringsArrayType;
|
||||
}
|
||||
else {
|
||||
// For context sensitive arguments we pass the identityMapper, which is a signal to treat all
|
||||
// context sensitive function expressions as wildcards
|
||||
var mapper = excludeArgument && excludeArgument[i] !== undefined ? identityMapper : inferenceMapper;
|
||||
var argType = checkExpressionWithContextualType(arg, paramType, mapper);
|
||||
}
|
||||
inferTypes(context, argType, paramType);
|
||||
}
|
||||
var parameterType = getTypeAtPosition(signature, i);
|
||||
if (i === 0 && args[i].parent.kind === SyntaxKind.TaggedTemplateExpression) {
|
||||
inferTypes(context, globalTemplateStringsArrayType, parameterType);
|
||||
continue;
|
||||
}
|
||||
// For context sensitive arguments we pass the identityMapper, which is a signal to treat all
|
||||
// context sensitive function expressions as wildcards
|
||||
var mapper = excludeArgument && excludeArgument[i] !== undefined ? identityMapper : inferenceMapper;
|
||||
inferTypes(context, checkExpressionWithContextualType(args[i], parameterType, mapper), parameterType);
|
||||
}
|
||||
|
||||
// In the second pass we visit only context sensitive arguments, and only those that aren't excluded, this
|
||||
@@ -6050,13 +6110,11 @@ module ts {
|
||||
// as we construct types for contextually typed parameters)
|
||||
if (excludeArgument) {
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
if (args[i].kind === SyntaxKind.OmittedExpression) {
|
||||
continue;
|
||||
}
|
||||
// No need to special-case tagged templates; their excludeArgument value will be 'undefined'.
|
||||
// No need to check for omitted args and template expressions, their exlusion value is always undefined
|
||||
if (excludeArgument[i] === false) {
|
||||
var parameterType = getTypeAtPosition(signature, i);
|
||||
inferTypes(context, checkExpressionWithContextualType(args[i], parameterType, inferenceMapper), parameterType);
|
||||
var arg = args[i];
|
||||
var paramType = getTypeAtPosition(signature, arg.kind === SyntaxKind.SpreadElementExpression ? -1 : i);
|
||||
inferTypes(context, checkExpressionWithContextualType(arg, paramType, inferenceMapper), paramType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6094,37 +6152,24 @@ module ts {
|
||||
return typeArgumentsAreAssignable;
|
||||
}
|
||||
|
||||
function checkApplicableSignature(node: CallLikeExpression, args: Node[], signature: Signature, relation: Map<RelationComparisonResult>, excludeArgument: boolean[], reportErrors: boolean) {
|
||||
function checkApplicableSignature(node: CallLikeExpression, args: Expression[], signature: Signature, relation: Map<RelationComparisonResult>, excludeArgument: boolean[], reportErrors: boolean) {
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
var arg = args[i];
|
||||
var argType: Type;
|
||||
|
||||
if (arg.kind === SyntaxKind.OmittedExpression) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var paramType = getTypeAtPosition(signature, i);
|
||||
|
||||
if (i === 0 && node.kind === SyntaxKind.TaggedTemplateExpression) {
|
||||
// A tagged template expression has something of a
|
||||
// "virtual" parameter with the "cooked" strings array type.
|
||||
argType = globalTemplateStringsArrayType;
|
||||
}
|
||||
else {
|
||||
// String literals get string literal types unless we're reporting errors
|
||||
argType = arg.kind === SyntaxKind.StringLiteral && !reportErrors
|
||||
? getStringLiteralType(<LiteralExpression>arg)
|
||||
: checkExpressionWithContextualType(<LiteralExpression>arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined);
|
||||
}
|
||||
|
||||
// Use argument expression as error location when reporting errors
|
||||
var isValidArgument = checkTypeRelatedTo(argType, paramType, relation, reportErrors ? arg : undefined,
|
||||
Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1);
|
||||
if (!isValidArgument) {
|
||||
return false;
|
||||
if (arg.kind !== SyntaxKind.OmittedExpression) {
|
||||
// Check spread elements against rest type (from arity check we know spread argument corresponds to a rest parameter)
|
||||
var paramType = getTypeAtPosition(signature, arg.kind === SyntaxKind.SpreadElementExpression ? -1 : i);
|
||||
// A tagged template expression provides a special first argument, and string literals get string literal types
|
||||
// unless we're reporting errors
|
||||
var argType = i === 0 && node.kind === SyntaxKind.TaggedTemplateExpression ? globalTemplateStringsArrayType :
|
||||
arg.kind === SyntaxKind.StringLiteral && !reportErrors ? getStringLiteralType(<LiteralExpression>arg) :
|
||||
checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined);
|
||||
// Use argument expression as error location when reporting errors
|
||||
if (!checkTypeRelatedTo(argType, paramType, relation, reportErrors ? arg : undefined,
|
||||
Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -6191,8 +6236,8 @@ module ts {
|
||||
}
|
||||
|
||||
var candidates = candidatesOutArray || [];
|
||||
// collectCandidates fills up the candidates array directly
|
||||
collectCandidates();
|
||||
// reorderCandidates fills up the candidates array directly
|
||||
reorderCandidates(signatures, candidates);
|
||||
if (!candidates.length) {
|
||||
error(node, Diagnostics.Supplied_parameters_do_not_match_any_signature_of_call_target);
|
||||
return resolveErrorCall(node);
|
||||
@@ -6382,60 +6427,6 @@ module ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// The candidate list orders groups in reverse, but within a group signatures are kept in declaration order
|
||||
// A nit here is that we reorder only signatures that belong to the same symbol,
|
||||
// so order how inherited signatures are processed is still preserved.
|
||||
// interface A { (x: string): void }
|
||||
// interface B extends A { (x: 'foo'): string }
|
||||
// var b: B;
|
||||
// b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void]
|
||||
function collectCandidates(): void {
|
||||
var result = candidates;
|
||||
var lastParent: Node;
|
||||
var lastSymbol: Symbol;
|
||||
var cutoffIndex: number = 0;
|
||||
var index: number;
|
||||
var specializedIndex: number = -1;
|
||||
var spliceIndex: number;
|
||||
Debug.assert(!result.length);
|
||||
for (var i = 0; i < signatures.length; i++) {
|
||||
var signature = signatures[i];
|
||||
var symbol = signature.declaration && getSymbolOfNode(signature.declaration);
|
||||
var parent = signature.declaration && signature.declaration.parent;
|
||||
if (!lastSymbol || symbol === lastSymbol) {
|
||||
if (lastParent && parent === lastParent) {
|
||||
index++;
|
||||
}
|
||||
else {
|
||||
lastParent = parent;
|
||||
index = cutoffIndex;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// current declaration belongs to a different symbol
|
||||
// set cutoffIndex so re-orderings in the future won't change result set from 0 to cutoffIndex
|
||||
index = cutoffIndex = result.length;
|
||||
lastParent = parent;
|
||||
}
|
||||
lastSymbol = symbol;
|
||||
|
||||
// specialized signatures always need to be placed before non-specialized signatures regardless
|
||||
// of the cutoff position; see GH#1133
|
||||
if (signature.hasStringLiterals) {
|
||||
specializedIndex++;
|
||||
spliceIndex = specializedIndex;
|
||||
// The cutoff index always needs to be greater than or equal to the specialized signature index
|
||||
// in order to prevent non-specialized signatures from being added before a specialized
|
||||
// signature.
|
||||
cutoffIndex++;
|
||||
}
|
||||
else {
|
||||
spliceIndex = index;
|
||||
}
|
||||
|
||||
result.splice(spliceIndex, 0, signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[]): Signature {
|
||||
@@ -6491,6 +6482,13 @@ module ts {
|
||||
}
|
||||
|
||||
function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[]): Signature {
|
||||
if (node.arguments && languageVersion < ScriptTarget.ES6) {
|
||||
var spreadIndex = getSpreadArgumentIndex(node.arguments);
|
||||
if (spreadIndex >= 0) {
|
||||
error(node.arguments[spreadIndex], Diagnostics.Spread_operator_in_new_expressions_is_only_available_when_targeting_ECMAScript_6_and_higher);
|
||||
}
|
||||
}
|
||||
|
||||
var expressionType = checkExpression(node.expression);
|
||||
// TS 1.0 spec: 4.11
|
||||
// If ConstructExpr is of type Any, Args can be any argument
|
||||
@@ -6636,9 +6634,14 @@ module ts {
|
||||
}
|
||||
|
||||
function getTypeAtPosition(signature: Signature, pos: number): Type {
|
||||
if (pos >= 0) {
|
||||
return signature.hasRestParameter ?
|
||||
pos < signature.parameters.length - 1 ? getTypeOfSymbol(signature.parameters[pos]) : getRestTypeOfSignature(signature) :
|
||||
pos < signature.parameters.length ? getTypeOfSymbol(signature.parameters[pos]) : anyType;
|
||||
}
|
||||
return signature.hasRestParameter ?
|
||||
pos < signature.parameters.length - 1 ? getTypeOfSymbol(signature.parameters[pos]) : getRestTypeOfSignature(signature) :
|
||||
pos < signature.parameters.length ? getTypeOfSymbol(signature.parameters[pos]) : anyType;
|
||||
getTypeOfSymbol(signature.parameters[signature.parameters.length - 1]) :
|
||||
anyArrayType;
|
||||
}
|
||||
|
||||
function assignContextualParameterTypes(signature: Signature, context: Signature, mapper: TypeMapper) {
|
||||
@@ -11085,9 +11088,32 @@ module ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var checkLetConstNames = languageVersion >= ScriptTarget.ES6 && (isLet(node) || isConst(node));
|
||||
|
||||
// 1. LexicalDeclaration : LetOrConst BindingList ;
|
||||
// It is a Syntax Error if the BoundNames of BindingList contains "let".
|
||||
// 2. ForDeclaration: ForDeclaration : LetOrConst ForBinding
|
||||
// It is a Syntax Error if the BoundNames of ForDeclaration contains "let".
|
||||
|
||||
// It is a SyntaxError if a VariableDeclaration or VariableDeclarationNoIn occurs within strict code
|
||||
// and its Identifier is eval or arguments
|
||||
return checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.name);
|
||||
return (checkLetConstNames && checkGrammarNameInLetOrConstDeclarations(node.name)) ||
|
||||
checkGrammarEvalOrArgumentsInStrictMode(node, <Identifier>node.name);
|
||||
}
|
||||
|
||||
function checkGrammarNameInLetOrConstDeclarations(name: Identifier | BindingPattern): boolean {
|
||||
if (name.kind === SyntaxKind.Identifier) {
|
||||
if ((<Identifier>name).text === "let") {
|
||||
return grammarErrorOnNode(name, Diagnostics.let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations);
|
||||
}
|
||||
}
|
||||
else {
|
||||
var elements = (<BindingPattern>name).elements;
|
||||
for (var i = 0; i < elements.length; ++i) {
|
||||
checkGrammarNameInLetOrConstDeclarations(elements[i].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkGrammarVariableDeclarationList(declarationList: VariableDeclarationList): boolean {
|
||||
|
||||
@@ -307,6 +307,7 @@ module ts {
|
||||
The_0_operator_cannot_be_applied_to_type_symbol: { code: 2469, category: DiagnosticCategory.Error, key: "The '{0}' operator cannot be applied to type 'symbol'." },
|
||||
Symbol_reference_does_not_refer_to_the_global_Symbol_constructor_object: { code: 2470, category: DiagnosticCategory.Error, key: "'Symbol' reference does not refer to the global Symbol constructor object." },
|
||||
A_computed_property_name_of_the_form_0_must_be_of_type_symbol: { code: 2471, category: DiagnosticCategory.Error, key: "A computed property name of the form '{0}' must be of type 'symbol'." },
|
||||
Spread_operator_in_new_expressions_is_only_available_when_targeting_ECMAScript_6_and_higher: { code: 2472, category: DiagnosticCategory.Error, key: "Spread operator in 'new' expressions is only available when targeting ECMAScript 6 and higher." },
|
||||
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
|
||||
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },
|
||||
Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4004, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using private name '{1}'." },
|
||||
@@ -383,6 +384,7 @@ module ts {
|
||||
const_enum_member_initializer_was_evaluated_to_a_non_finite_value: { code: 4086, category: DiagnosticCategory.Error, key: "'const' enum member initializer was evaluated to a non-finite value." },
|
||||
const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN: { code: 4087, category: DiagnosticCategory.Error, key: "'const' enum member initializer was evaluated to disallowed value 'NaN'." },
|
||||
Property_0_does_not_exist_on_const_enum_1: { code: 4088, category: DiagnosticCategory.Error, key: "Property '{0}' does not exist on 'const' enum '{1}'." },
|
||||
let_is_not_allowed_to_be_used_as_a_name_in_let_or_const_declarations: { code: 4089, category: DiagnosticCategory.Error, key: "'let' is not allowed to be used as a name in 'let' or 'const' declarations." },
|
||||
The_current_host_does_not_support_the_0_option: { code: 5001, category: DiagnosticCategory.Error, key: "The current host does not support the '{0}' option." },
|
||||
Cannot_find_the_common_subdirectory_path_for_the_input_files: { code: 5009, category: DiagnosticCategory.Error, key: "Cannot find the common subdirectory path for the input files." },
|
||||
Cannot_read_file_0_Colon_1: { code: 5012, category: DiagnosticCategory.Error, key: "Cannot read file '{0}': {1}" },
|
||||
|
||||
@@ -1220,6 +1220,10 @@
|
||||
"category": "Error",
|
||||
"code": 2471
|
||||
},
|
||||
"Spread operator in 'new' expressions is only available when targeting ECMAScript 6 and higher.": {
|
||||
"category": "Error",
|
||||
"code": 2472
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
@@ -1525,6 +1529,10 @@
|
||||
"category": "Error",
|
||||
"code": 4088
|
||||
},
|
||||
"'let' is not allowed to be used as a name in 'let' or 'const' declarations.": {
|
||||
"category": "Error",
|
||||
"code": 4089
|
||||
},
|
||||
"The current host does not support the '{0}' option.": {
|
||||
"category": "Error",
|
||||
"code": 5001
|
||||
|
||||
+94
-17
@@ -1998,7 +1998,7 @@ module ts {
|
||||
break;
|
||||
}
|
||||
// _a .. _h, _j ... _z, _0, _1, ...
|
||||
name = "_" + (tempCount < 25 ? String.fromCharCode(tempCount + (tempCount < 8 ? 0: 1) + CharacterCodes.a) : tempCount - 25);
|
||||
name = "_" + (tempCount < 25 ? String.fromCharCode(tempCount + (tempCount < 8 ? 0 : 1) + CharacterCodes.a) : tempCount - 25);
|
||||
tempCount++;
|
||||
}
|
||||
var result = <Identifier>createNode(SyntaxKind.Identifier);
|
||||
@@ -2427,22 +2427,10 @@ module ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
function emitArrayLiteral(node: ArrayLiteralExpression) {
|
||||
var elements = node.elements;
|
||||
var length = elements.length;
|
||||
if (length === 0) {
|
||||
write("[]");
|
||||
return;
|
||||
}
|
||||
if (languageVersion >= ScriptTarget.ES6) {
|
||||
write("[");
|
||||
emitList(elements, 0, elements.length, /*multiLine*/(node.flags & NodeFlags.MultiLine) !== 0,
|
||||
/*trailingComma*/ elements.hasTrailingComma);
|
||||
write("]");
|
||||
return;
|
||||
}
|
||||
function emitListWithSpread(elements: Expression[], multiLine: boolean, trailingComma: boolean) {
|
||||
var pos = 0;
|
||||
var group = 0;
|
||||
var length = elements.length;
|
||||
while (pos < length) {
|
||||
// Emit using the pattern <group0>.concat(<group1>, <group2>, ...)
|
||||
if (group === 1) {
|
||||
@@ -2463,8 +2451,7 @@ module ts {
|
||||
i++;
|
||||
}
|
||||
write("[");
|
||||
emitList(elements, pos, i - pos, /*multiLine*/ (node.flags & NodeFlags.MultiLine) !== 0,
|
||||
/*trailingComma*/ elements.hasTrailingComma);
|
||||
emitList(elements, pos, i - pos, multiLine, trailingComma && i === length);
|
||||
write("]");
|
||||
pos = i;
|
||||
}
|
||||
@@ -2475,6 +2462,23 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function emitArrayLiteral(node: ArrayLiteralExpression) {
|
||||
var elements = node.elements;
|
||||
if (elements.length === 0) {
|
||||
write("[]");
|
||||
}
|
||||
else if (languageVersion >= ScriptTarget.ES6) {
|
||||
write("[");
|
||||
emitList(elements, 0, elements.length, /*multiLine*/ (node.flags & NodeFlags.MultiLine) !== 0,
|
||||
/*trailingComma*/ elements.hasTrailingComma);
|
||||
write("]");
|
||||
}
|
||||
else {
|
||||
emitListWithSpread(elements, /*multiLine*/ (node.flags & NodeFlags.MultiLine) !== 0,
|
||||
/*trailingComma*/ elements.hasTrailingComma);
|
||||
}
|
||||
}
|
||||
|
||||
function emitObjectLiteral(node: ObjectLiteralExpression) {
|
||||
write("{");
|
||||
var properties = node.properties;
|
||||
@@ -2569,7 +2573,80 @@ module ts {
|
||||
write("]");
|
||||
}
|
||||
|
||||
function hasSpreadElement(elements: Expression[]) {
|
||||
return forEach(elements, e => e.kind === SyntaxKind.SpreadElementExpression);
|
||||
}
|
||||
|
||||
function skipParentheses(node: Expression): Expression {
|
||||
while (node.kind === SyntaxKind.ParenthesizedExpression || node.kind === SyntaxKind.TypeAssertionExpression) {
|
||||
node = (<ParenthesizedExpression | TypeAssertion>node).expression;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
function emitCallTarget(node: Expression): Expression {
|
||||
if (node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.SuperKeyword) {
|
||||
emit(node);
|
||||
return node;
|
||||
}
|
||||
var temp = createTempVariable(node);
|
||||
recordTempDeclaration(temp);
|
||||
write("(");
|
||||
emit(temp);
|
||||
write(" = ");
|
||||
emit(node);
|
||||
write(")");
|
||||
return temp;
|
||||
}
|
||||
|
||||
function emitCallWithSpread(node: CallExpression) {
|
||||
var target: Expression;
|
||||
var expr = skipParentheses(node.expression);
|
||||
if (expr.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
// Target will be emitted as "this" argument
|
||||
target = emitCallTarget((<PropertyAccessExpression>expr).expression);
|
||||
write(".");
|
||||
emit((<PropertyAccessExpression>expr).name);
|
||||
}
|
||||
else if (expr.kind === SyntaxKind.ElementAccessExpression) {
|
||||
// Target will be emitted as "this" argument
|
||||
target = emitCallTarget((<PropertyAccessExpression>expr).expression);
|
||||
write("[");
|
||||
emit((<ElementAccessExpression>expr).argumentExpression);
|
||||
write("]");
|
||||
}
|
||||
else if (expr.kind === SyntaxKind.SuperKeyword) {
|
||||
target = expr;
|
||||
write("_super");
|
||||
}
|
||||
else {
|
||||
emit(node.expression);
|
||||
}
|
||||
write(".apply(");
|
||||
if (target) {
|
||||
if (target.kind === SyntaxKind.SuperKeyword) {
|
||||
// Calls of form super(...) and super.foo(...)
|
||||
emitThis(target);
|
||||
}
|
||||
else {
|
||||
// Calls of form obj.foo(...)
|
||||
emit(target);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Calls of form foo(...)
|
||||
write("void 0");
|
||||
}
|
||||
write(", ");
|
||||
emitListWithSpread(node.arguments, /*multiLine*/ false, /*trailingComma*/ false);
|
||||
write(")");
|
||||
}
|
||||
|
||||
function emitCallExpression(node: CallExpression) {
|
||||
if (languageVersion < ScriptTarget.ES6 && hasSpreadElement(node.arguments)) {
|
||||
emitCallWithSpread(node);
|
||||
return;
|
||||
}
|
||||
var superCall = false;
|
||||
if (node.expression.kind === SyntaxKind.SuperKeyword) {
|
||||
write("_super");
|
||||
|
||||
+149
-75
@@ -336,11 +336,16 @@ module ts {
|
||||
}
|
||||
|
||||
function fixupParentReferences(sourceFile: SourceFile) {
|
||||
// normally parent references are set during binding.
|
||||
// however here SourceFile data is used only for syntactic features so running the whole binding process is an overhead.
|
||||
// walk over the nodes and set parent references
|
||||
// normally parent references are set during binding. However, for clients that only need
|
||||
// a syntax tree, and no semantic features, then the binding process is an unnecessary
|
||||
// overhead. This functions allows us to set all the parents, without all the expense of
|
||||
// binding.
|
||||
|
||||
var parent: Node = sourceFile;
|
||||
function walk(n: Node): void {
|
||||
forEachChild(sourceFile, visitNode);
|
||||
return;
|
||||
|
||||
function visitNode(n: Node): void {
|
||||
// walk down setting parents that differ from the parent we think it should be. This
|
||||
// allows us to quickly bail out of setting parents for subtrees during incremental
|
||||
// parsing
|
||||
@@ -349,33 +354,53 @@ module ts {
|
||||
|
||||
var saveParent = parent;
|
||||
parent = n;
|
||||
forEachChild(n, walk);
|
||||
forEachChild(n, visitNode);
|
||||
parent = saveParent;
|
||||
}
|
||||
}
|
||||
|
||||
forEachChild(sourceFile, walk);
|
||||
}
|
||||
|
||||
function moveElementEntirelyPastChangeRange(element: IncrementalElement, delta: number) {
|
||||
if (element.length) {
|
||||
function shouldCheckNode(node: Node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.Identifier:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function moveElementEntirelyPastChangeRange(element: IncrementalElement, isArray: boolean, delta: number, oldText: string, newText: string, aggressiveChecks: boolean) {
|
||||
if (isArray) {
|
||||
visitArray(<IncrementalNodeArray>element);
|
||||
}
|
||||
else {
|
||||
visitNode(<IncrementalNode>element);
|
||||
}
|
||||
return;
|
||||
|
||||
function visitNode(node: IncrementalNode) {
|
||||
if (aggressiveChecks && shouldCheckNode(node)) {
|
||||
var text = oldText.substring(node.pos, node.end);
|
||||
}
|
||||
|
||||
// Ditch any existing LS children we may have created. This way we can avoid
|
||||
// moving them forward.
|
||||
node._children = undefined;
|
||||
node.pos += delta;
|
||||
node.end += delta;
|
||||
|
||||
if (aggressiveChecks && shouldCheckNode(node)) {
|
||||
Debug.assert(text === newText.substring(node.pos, node.end));
|
||||
}
|
||||
|
||||
forEachChild(node, visitNode, visitArray);
|
||||
checkNodePositions(node, aggressiveChecks);
|
||||
}
|
||||
|
||||
function visitArray(array: IncrementalNodeArray) {
|
||||
array._children = undefined;
|
||||
array.pos += delta;
|
||||
array.end += delta;
|
||||
|
||||
@@ -388,6 +413,7 @@ module ts {
|
||||
function adjustIntersectingElement(element: IncrementalElement, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number) {
|
||||
Debug.assert(element.end >= changeStart, "Adjusting an element that was entirely before the change range");
|
||||
Debug.assert(element.pos <= changeRangeOldEnd, "Adjusting an element that was entirely after the change range");
|
||||
Debug.assert(element.pos <= element.end);
|
||||
|
||||
// We have an element that intersects the change range in some way. It may have its
|
||||
// start, or its end (or both) in the changed range. We want to adjust any part
|
||||
@@ -459,14 +485,36 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function updateTokenPositionsAndMarkElements(node: IncrementalNode, changeStart: number, changeRangeOldEnd: number, changeRangeNewEnd: number, delta: number): void {
|
||||
visitNode(node);
|
||||
function checkNodePositions(node: Node, aggressiveChecks: boolean) {
|
||||
if (aggressiveChecks) {
|
||||
var pos = node.pos;
|
||||
forEachChild(node, child => {
|
||||
Debug.assert(child.pos >= pos);
|
||||
pos = child.end;
|
||||
});
|
||||
Debug.assert(pos <= node.end);
|
||||
}
|
||||
}
|
||||
|
||||
function updateTokenPositionsAndMarkElements(
|
||||
sourceFile: IncrementalNode,
|
||||
changeStart: number,
|
||||
changeRangeOldEnd: number,
|
||||
changeRangeNewEnd: number,
|
||||
delta: number,
|
||||
oldText: string,
|
||||
newText: string,
|
||||
aggressiveChecks: boolean): void {
|
||||
|
||||
visitNode(sourceFile);
|
||||
return;
|
||||
|
||||
function visitNode(child: IncrementalNode) {
|
||||
Debug.assert(child.pos <= child.end);
|
||||
if (child.pos > changeRangeOldEnd) {
|
||||
// Node is entirely past the change range. We need to move both its pos and
|
||||
// end, forward or backward appropriately.
|
||||
moveElementEntirelyPastChangeRange(child, delta);
|
||||
moveElementEntirelyPastChangeRange(child, /*isArray:*/ false, delta, oldText, newText, aggressiveChecks);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -476,44 +524,50 @@ module ts {
|
||||
var fullEnd = child.end;
|
||||
if (fullEnd >= changeStart) {
|
||||
child.intersectsChange = true;
|
||||
child._children = undefined;
|
||||
|
||||
// Adjust the pos or end (or both) of the intersecting element accordingly.
|
||||
adjustIntersectingElement(child, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta);
|
||||
forEachChild(child, visitNode, visitArray);
|
||||
|
||||
checkNodePositions(child, aggressiveChecks);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, the node is entirely before the change range. No need to do anything with it.
|
||||
Debug.assert(fullEnd < changeStart);
|
||||
}
|
||||
|
||||
function visitArray(array: IncrementalNodeArray) {
|
||||
Debug.assert(array.pos <= array.end);
|
||||
if (array.pos > changeRangeOldEnd) {
|
||||
// Array is entirely after the change range. We need to move it, and move any of
|
||||
// its children.
|
||||
moveElementEntirelyPastChangeRange(array, delta);
|
||||
moveElementEntirelyPastChangeRange(array, /*isArray:*/ true, delta, oldText, newText, aggressiveChecks);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
// Check if the element intersects the change range. If it does, then it is not
|
||||
// reusable. Also, we'll need to recurse to see what constituent portions we may
|
||||
// be able to use.
|
||||
var fullEnd = array.end;
|
||||
if (fullEnd >= changeStart) {
|
||||
array.intersectsChange = true;
|
||||
|
||||
// Adjust the pos or end (or both) of the intersecting array accordingly.
|
||||
adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta);
|
||||
for (var i = 0, n = array.length; i < n; i++) {
|
||||
visitNode(array[i]);
|
||||
}
|
||||
// Check if the element intersects the change range. If it does, then it is not
|
||||
// reusable. Also, we'll need to recurse to see what constituent portions we may
|
||||
// be able to use.
|
||||
var fullEnd = array.end;
|
||||
if (fullEnd >= changeStart) {
|
||||
array.intersectsChange = true;
|
||||
array._children = undefined;
|
||||
|
||||
// Adjust the pos or end (or both) of the intersecting array accordingly.
|
||||
adjustIntersectingElement(array, changeStart, changeRangeOldEnd, changeRangeNewEnd, delta);
|
||||
for (var i = 0, n = array.length; i < n; i++) {
|
||||
visitNode(array[i]);
|
||||
}
|
||||
// else {
|
||||
// Otherwise, the array is entirely before the change range. No need to do anything with it.
|
||||
// }
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, the array is entirely before the change range. No need to do anything with it.
|
||||
Debug.assert(fullEnd < changeStart);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function extendToAffectedRange(sourceFile: SourceFile, changeRange: TextChangeRange): TextChangeRange {
|
||||
// Consider the following code:
|
||||
// void foo() { /; }
|
||||
@@ -534,6 +588,7 @@ module ts {
|
||||
// start of the tree.
|
||||
for (var i = 0; start > 0 && i <= maxLookahead; i++) {
|
||||
var nearestNode = findNearestNodeStartingBeforeOrAtPosition(sourceFile, start);
|
||||
Debug.assert(nearestNode.pos <= start);
|
||||
var position = nearestNode.pos;
|
||||
|
||||
start = Math.max(0, position - 1);
|
||||
@@ -640,6 +695,22 @@ module ts {
|
||||
}
|
||||
}
|
||||
|
||||
function checkChangeRange(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks: boolean) {
|
||||
var oldText = sourceFile.text;
|
||||
if (textChangeRange) {
|
||||
Debug.assert((oldText.length - textChangeRange.span.length + textChangeRange.newLength) === newText.length);
|
||||
|
||||
if (aggressiveChecks || Debug.shouldAssert(AssertionLevel.VeryAggressive)) {
|
||||
var oldTextPrefix = oldText.substr(0, textChangeRange.span.start);
|
||||
var newTextPrefix = newText.substr(0, textChangeRange.span.start);
|
||||
Debug.assert(oldTextPrefix === newTextPrefix);
|
||||
|
||||
var oldTextSuffix = oldText.substring(textSpanEnd(textChangeRange.span), oldText.length);
|
||||
var newTextSuffix = newText.substring(textSpanEnd(textChangeRangeNewSpan(textChangeRange)), newText.length);
|
||||
Debug.assert(oldTextSuffix === newTextSuffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter
|
||||
// indicates what changed between the 'text' that this SourceFile has and the 'newText'.
|
||||
@@ -650,7 +721,10 @@ module ts {
|
||||
// from this SourceFile that are being held onto may change as a result (including
|
||||
// becoming detached from any SourceFile). It is recommended that this SourceFile not
|
||||
// be used once 'update' is called on it.
|
||||
export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile {
|
||||
export function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile {
|
||||
aggressiveChecks = aggressiveChecks || Debug.shouldAssert(AssertionLevel.Aggressive);
|
||||
|
||||
checkChangeRange(sourceFile, newText, textChangeRange, aggressiveChecks);
|
||||
if (textChangeRangeIsUnchanged(textChangeRange)) {
|
||||
// if the text didn't change, then we can just return our current source file as-is.
|
||||
return sourceFile;
|
||||
@@ -659,14 +733,32 @@ module ts {
|
||||
if (sourceFile.statements.length === 0) {
|
||||
// If we don't have any statements in the current source file, then there's no real
|
||||
// way to incrementally parse. So just do a full parse instead.
|
||||
return parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion,/*syntaxCursor*/ undefined, /*setNodeParents*/ true)
|
||||
return parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setNodeParents*/ true)
|
||||
}
|
||||
|
||||
// Make sure we're not trying to incrementally update a source file more than once. Once
|
||||
// we do an update the original source file is considered unusbale from that point onwards.
|
||||
//
|
||||
// This is because we do incremental parsing in-place. i.e. we take nodes from the old
|
||||
// tree and give them new positions and parents. From that point on, trusting the old
|
||||
// tree at all is not possible as far too much of it may violate invariants.
|
||||
var incrementalSourceFile = <IncrementalNode><Node>sourceFile;
|
||||
Debug.assert(!incrementalSourceFile.hasBeenIncrementallyParsed);
|
||||
incrementalSourceFile.hasBeenIncrementallyParsed = true;
|
||||
|
||||
var oldText = sourceFile.text;
|
||||
var syntaxCursor = createSyntaxCursor(sourceFile);
|
||||
|
||||
// Make the actual change larger so that we know to reparse anything whose lookahead
|
||||
// might have intersected the change.
|
||||
var changeRange = extendToAffectedRange(sourceFile, textChangeRange);
|
||||
checkChangeRange(sourceFile, newText, changeRange, aggressiveChecks);
|
||||
|
||||
// Ensure that extending the affected range only moved the start of the change range
|
||||
// earlier in the file.
|
||||
Debug.assert(changeRange.span.start <= textChangeRange.span.start);
|
||||
Debug.assert(textSpanEnd(changeRange.span) === textSpanEnd(textChangeRange.span));
|
||||
Debug.assert(textSpanEnd(textChangeRangeNewSpan(changeRange)) === textSpanEnd(textChangeRangeNewSpan(textChangeRange)));
|
||||
|
||||
// The is the amount the nodes after the edit range need to be adjusted. It can be
|
||||
// positive (if the edit added characters), negative (if the edit deleted characters)
|
||||
@@ -674,8 +766,8 @@ module ts {
|
||||
var delta = textChangeRangeNewSpan(changeRange).length - changeRange.span.length;
|
||||
|
||||
// If we added or removed characters during the edit, then we need to go and adjust all
|
||||
// the nodes after the edit. Those nodes may move forward down (if we inserted chars)
|
||||
// or they may move backward (if we deleted chars).
|
||||
// the nodes after the edit. Those nodes may move forward (if we inserted chars) or they
|
||||
// may move backward (if we deleted chars).
|
||||
//
|
||||
// Doing this helps us out in two ways. First, it means that any nodes/tokens we want
|
||||
// to reuse are already at the appropriate position in the new text. That way when we
|
||||
@@ -692,8 +784,8 @@ module ts {
|
||||
//
|
||||
// Also, mark any syntax elements that intersect the changed span. We know, up front,
|
||||
// that we cannot reuse these elements.
|
||||
updateTokenPositionsAndMarkElements(<IncrementalNode><Node>sourceFile,
|
||||
changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta);
|
||||
updateTokenPositionsAndMarkElements(incrementalSourceFile,
|
||||
changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta, oldText, newText, aggressiveChecks);
|
||||
|
||||
// Now that we've set up our internal incremental state just proceed and parse the
|
||||
// source file in the normal fashion. When possible the parser will retrieve and
|
||||
@@ -733,6 +825,7 @@ module ts {
|
||||
}
|
||||
|
||||
interface IncrementalNode extends Node, IncrementalElement {
|
||||
hasBeenIncrementallyParsed: boolean
|
||||
}
|
||||
|
||||
interface IncrementalNodeArray extends NodeArray<IncrementalNode>, IncrementalElement {
|
||||
@@ -768,7 +861,7 @@ module ts {
|
||||
// Much of the time the parser will need the very next node in the array that
|
||||
// we just returned a node from.So just simply check for that case and move
|
||||
// forward in the array instead of searching for the node again.
|
||||
if (current && current.end === position && currentArrayIndex < currentArray.length) {
|
||||
if (current && current.end === position && currentArrayIndex < (currentArray.length - 1)) {
|
||||
currentArrayIndex++;
|
||||
current = currentArray[currentArrayIndex];
|
||||
}
|
||||
@@ -804,6 +897,7 @@ module ts {
|
||||
|
||||
// Recurse into the source file to find the highest node at this position.
|
||||
forEachChild(sourceFile, visitNode, visitArray);
|
||||
return;
|
||||
|
||||
function visitNode(node: Node) {
|
||||
if (position >= node.pos && position < node.end) {
|
||||
@@ -863,7 +957,6 @@ module ts {
|
||||
var identifiers: Map<string> = {};
|
||||
var identifierCount = 0;
|
||||
var nodeCount = 0;
|
||||
var scanner: Scanner;
|
||||
var token: SyntaxKind;
|
||||
|
||||
var sourceFile = <SourceFile>createNode(SyntaxKind.SourceFile, /*pos*/ 0);
|
||||
@@ -956,7 +1049,7 @@ module ts {
|
||||
var parseErrorBeforeNextFinishedNode: boolean = false;
|
||||
|
||||
// Create and prime the scanner before parsing the source elements.
|
||||
scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceText, scanError);
|
||||
var scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceText, scanError);
|
||||
token = nextToken();
|
||||
|
||||
processReferenceComments(sourceFile);
|
||||
@@ -975,6 +1068,7 @@ module ts {
|
||||
fixupParentReferences(sourceFile);
|
||||
}
|
||||
|
||||
syntaxCursor = undefined;
|
||||
return sourceFile;
|
||||
|
||||
function setContextFlag(val: Boolean, flag: ParserContextFlags) {
|
||||
@@ -1422,7 +1516,6 @@ module ts {
|
||||
case ParsingContext.TypeParameters:
|
||||
return isIdentifier();
|
||||
case ParsingContext.ArgumentExpressions:
|
||||
return token === SyntaxKind.CommaToken || isStartOfExpression();
|
||||
case ParsingContext.ArrayLiteralMembers:
|
||||
return token === SyntaxKind.CommaToken || token === SyntaxKind.DotDotDotToken || isStartOfExpression();
|
||||
case ParsingContext.Parameters:
|
||||
@@ -1575,8 +1668,8 @@ module ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function parseListElement<T extends Node>(kind: ParsingContext, parseElement: () => T): T {
|
||||
var node = currentNode(kind);
|
||||
function parseListElement<T extends Node>(parsingContext: ParsingContext, parseElement: () => T): T {
|
||||
var node = currentNode(parsingContext);
|
||||
if (node) {
|
||||
return <T>consumeNode(node);
|
||||
}
|
||||
@@ -1733,29 +1826,10 @@ module ts {
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration:
|
||||
case SyntaxKind.EnumDeclaration:
|
||||
|
||||
// Keep in sync with isStatement:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.VariableStatement:
|
||||
case SyntaxKind.Block:
|
||||
case SyntaxKind.IfStatement:
|
||||
case SyntaxKind.ExpressionStatement:
|
||||
case SyntaxKind.ThrowStatement:
|
||||
case SyntaxKind.ReturnStatement:
|
||||
case SyntaxKind.SwitchStatement:
|
||||
case SyntaxKind.BreakStatement:
|
||||
case SyntaxKind.ContinueStatement:
|
||||
case SyntaxKind.ForInStatement:
|
||||
case SyntaxKind.ForStatement:
|
||||
case SyntaxKind.WhileStatement:
|
||||
case SyntaxKind.WithStatement:
|
||||
case SyntaxKind.EmptyStatement:
|
||||
case SyntaxKind.TryStatement:
|
||||
case SyntaxKind.LabeledStatement:
|
||||
case SyntaxKind.DoStatement:
|
||||
case SyntaxKind.DebuggerStatement:
|
||||
return true;
|
||||
}
|
||||
|
||||
return isReusableStatement(node);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -1861,9 +1935,13 @@ module ts {
|
||||
}
|
||||
|
||||
function isReusableParameter(node: Node) {
|
||||
// TODO: this most likely needs the same initializer check that
|
||||
// isReusableVariableDeclaration has.
|
||||
return node.kind === SyntaxKind.Parameter;
|
||||
if (node.kind !== SyntaxKind.Parameter) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// See the comment in isReusableVariableDeclaration for why we do this.
|
||||
var parameter = <ParameterDeclaration>node;
|
||||
return parameter.initializer === undefined;
|
||||
}
|
||||
|
||||
// Returns true if we should abort parsing.
|
||||
@@ -3528,12 +3606,6 @@ module ts {
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseAssignmentExpressionOrOmittedExpression(): Expression {
|
||||
return token === SyntaxKind.CommaToken
|
||||
? <Expression>createNode(SyntaxKind.OmittedExpression)
|
||||
: parseAssignmentExpressionOrHigher();
|
||||
}
|
||||
|
||||
function parseSpreadElement(): Expression {
|
||||
var node = <SpreadElementExpression>createNode(SyntaxKind.SpreadElementExpression);
|
||||
parseExpected(SyntaxKind.DotDotDotToken);
|
||||
@@ -3541,19 +3613,21 @@ module ts {
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseArrayLiteralElement(): Expression {
|
||||
return token === SyntaxKind.DotDotDotToken ? parseSpreadElement() : parseAssignmentExpressionOrOmittedExpression();
|
||||
function parseArgumentOrArrayLiteralElement(): Expression {
|
||||
return token === SyntaxKind.DotDotDotToken ? parseSpreadElement() :
|
||||
token === SyntaxKind.CommaToken ? <Expression>createNode(SyntaxKind.OmittedExpression) :
|
||||
parseAssignmentExpressionOrHigher();
|
||||
}
|
||||
|
||||
function parseArgumentExpression(): Expression {
|
||||
return allowInAnd(parseAssignmentExpressionOrOmittedExpression);
|
||||
return allowInAnd(parseArgumentOrArrayLiteralElement);
|
||||
}
|
||||
|
||||
function parseArrayLiteralExpression(): ArrayLiteralExpression {
|
||||
var node = <ArrayLiteralExpression>createNode(SyntaxKind.ArrayLiteralExpression);
|
||||
parseExpected(SyntaxKind.OpenBracketToken);
|
||||
if (scanner.hasPrecedingLineBreak()) node.flags |= NodeFlags.MultiLine;
|
||||
node.elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArrayLiteralElement);
|
||||
node.elements = parseDelimitedList(ParsingContext.ArrayLiteralMembers, parseArgumentOrArrayLiteralElement);
|
||||
parseExpected(SyntaxKind.CloseBracketToken);
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
+89
-141
@@ -16,6 +16,7 @@
|
||||
/// <reference path='..\services\services.ts' />
|
||||
/// <reference path='harnessLanguageService.ts' />
|
||||
/// <reference path='harness.ts' />
|
||||
/// <reference path='fourslashRunner.ts' />
|
||||
|
||||
module FourSlash {
|
||||
ts.disableIncrementalParsing = false;
|
||||
@@ -245,11 +246,9 @@ module FourSlash {
|
||||
|
||||
export class TestState {
|
||||
// Language service instance
|
||||
public languageServiceShimHost: Harness.LanguageService.TypeScriptLS;
|
||||
private languageServiceAdapterHost: Harness.LanguageService.LanguageServiceAdapterHost;
|
||||
private languageService: ts.LanguageService;
|
||||
|
||||
// A reference to the language service's compiler state's compiler instance
|
||||
private compiler: () => { getSyntaxTree(fileName: string): ts.SourceFile };
|
||||
private cancellationToken: TestCancellationToken;
|
||||
|
||||
// The current caret position in the active file
|
||||
public currentCaretPosition = 0;
|
||||
@@ -263,8 +262,6 @@ module FourSlash {
|
||||
|
||||
public formatCodeOptions: ts.FormatCodeOptions;
|
||||
|
||||
public cancellationToken: TestCancellationToken;
|
||||
|
||||
private scenarioActions: string[] = [];
|
||||
private taoInvalidReason: string = null;
|
||||
|
||||
@@ -275,19 +272,31 @@ module FourSlash {
|
||||
private addMatchedInputFile(referenceFilePath: string) {
|
||||
var inputFile = this.inputFiles[referenceFilePath];
|
||||
if (inputFile && !Harness.isLibraryFile(referenceFilePath)) {
|
||||
this.languageServiceShimHost.addScript(referenceFilePath, inputFile);
|
||||
this.languageServiceAdapterHost.addScript(referenceFilePath, inputFile);
|
||||
}
|
||||
}
|
||||
|
||||
constructor(public testData: FourSlashData) {
|
||||
// Initialize the language service with all the scripts
|
||||
private getLanguageServiceAdapter(testType: FourSlashTestType, cancellationToken: TestCancellationToken, compilationOptions: ts.CompilerOptions): Harness.LanguageService.LanguageServiceAdapter {
|
||||
switch (testType) {
|
||||
case FourSlashTestType.Native:
|
||||
return new Harness.LanguageService.NativeLanugageServiceAdapter(cancellationToken, compilationOptions);
|
||||
case FourSlashTestType.Shims:
|
||||
return new Harness.LanguageService.ShimLanugageServiceAdapter(cancellationToken, compilationOptions);
|
||||
default:
|
||||
throw new Error("Unknown FourSlash test type: ");
|
||||
}
|
||||
}
|
||||
|
||||
constructor(private basePath: string, private testType: FourSlashTestType, public testData: FourSlashData) {
|
||||
// Create a new Services Adapter
|
||||
this.cancellationToken = new TestCancellationToken();
|
||||
this.languageServiceShimHost = new Harness.LanguageService.TypeScriptLS(this.cancellationToken);
|
||||
var compilationOptions = convertGlobalOptionsToCompilerOptions(this.testData.globalOptions);
|
||||
var languageServiceAdapter = this.getLanguageServiceAdapter(testType, this.cancellationToken, compilationOptions);
|
||||
this.languageServiceAdapterHost = languageServiceAdapter.getHost();
|
||||
this.languageService = languageServiceAdapter.getLanguageService();
|
||||
|
||||
var compilationSettings = convertGlobalOptionsToCompilerOptions(this.testData.globalOptions);
|
||||
this.languageServiceShimHost.setCompilationSettings(compilationSettings);
|
||||
|
||||
var startResolveFileRef: FourSlashFile = undefined;
|
||||
// Initialize the language service with all the scripts
|
||||
var startResolveFileRef: FourSlashFile;
|
||||
|
||||
ts.forEach(testData.files, file => {
|
||||
// Create map between fileName and its content for easily looking up when resolveReference flag is specified
|
||||
@@ -302,18 +311,16 @@ module FourSlash {
|
||||
|
||||
if (startResolveFileRef) {
|
||||
// Add the entry-point file itself into the languageServiceShimHost
|
||||
this.languageServiceShimHost.addScript(startResolveFileRef.fileName, startResolveFileRef.content);
|
||||
this.languageServiceAdapterHost.addScript(startResolveFileRef.fileName, startResolveFileRef.content);
|
||||
|
||||
var jsonResolvedResult = JSON.parse(this.languageServiceShimHost.getCoreService().getPreProcessedFileInfo(startResolveFileRef.fileName,
|
||||
createScriptSnapShot(startResolveFileRef.content)));
|
||||
var resolvedResult = jsonResolvedResult.result;
|
||||
var referencedFiles: ts.IFileReference[] = resolvedResult.referencedFiles;
|
||||
var importedFiles: ts.IFileReference[] = resolvedResult.importedFiles;
|
||||
var resolvedResult = languageServiceAdapter.getPreProcessedFileInfo(startResolveFileRef.fileName, startResolveFileRef.content);
|
||||
var referencedFiles: ts.FileReference[] = resolvedResult.referencedFiles;
|
||||
var importedFiles: ts.FileReference[] = resolvedResult.importedFiles;
|
||||
|
||||
// Add triple reference files into language-service host
|
||||
ts.forEach(referencedFiles, referenceFile => {
|
||||
// Fourslash insert tests/cases/fourslash into inputFile.unitName so we will properly append the same base directory to refFile path
|
||||
var referenceFilePath = "tests/cases/fourslash/" + referenceFile.path;
|
||||
var referenceFilePath = this.basePath + '/' + referenceFile.fileName;
|
||||
this.addMatchedInputFile(referenceFilePath);
|
||||
});
|
||||
|
||||
@@ -321,29 +328,24 @@ module FourSlash {
|
||||
ts.forEach(importedFiles, importedFile => {
|
||||
// Fourslash insert tests/cases/fourslash into inputFile.unitName and import statement doesn't require ".ts"
|
||||
// so convert them before making appropriate comparison
|
||||
var importedFilePath = "tests/cases/fourslash/" + importedFile.path + ".ts";
|
||||
var importedFilePath = this.basePath + '/' + importedFile.fileName + ".ts";
|
||||
this.addMatchedInputFile(importedFilePath);
|
||||
});
|
||||
|
||||
// Check if no-default-lib flag is false and if so add default library
|
||||
if (!resolvedResult.isLibFile) {
|
||||
this.languageServiceShimHost.addDefaultLibrary();
|
||||
this.languageServiceAdapterHost.addScript(Harness.Compiler.defaultLibFileName, Harness.Compiler.defaultLibSourceFile.text);
|
||||
}
|
||||
} else {
|
||||
// resolveReference file-option is not specified then do not resolve any files and include all inputFiles
|
||||
ts.forEachKey(this.inputFiles, fileName => {
|
||||
if (!Harness.isLibraryFile(fileName)) {
|
||||
this.languageServiceShimHost.addScript(fileName, this.inputFiles[fileName]);
|
||||
this.languageServiceAdapterHost.addScript(fileName, this.inputFiles[fileName]);
|
||||
}
|
||||
});
|
||||
this.languageServiceShimHost.addDefaultLibrary();
|
||||
this.languageServiceAdapterHost.addScript(Harness.Compiler.defaultLibFileName, Harness.Compiler.defaultLibSourceFile.text);
|
||||
}
|
||||
|
||||
// Sneak into the language service and get its compiler so we can examine the syntax trees
|
||||
this.languageService = this.languageServiceShimHost.getLanguageService().languageService;
|
||||
var compilerState = (<any>this.languageService).compiler;
|
||||
this.compiler = () => compilerState.compiler;
|
||||
|
||||
this.formatCodeOptions = {
|
||||
IndentSize: 4,
|
||||
TabSize: 4,
|
||||
@@ -369,6 +371,11 @@ module FourSlash {
|
||||
this.openFile(0);
|
||||
}
|
||||
|
||||
private getFileContent(fileName: string): string {
|
||||
var script = this.languageServiceAdapterHost.getScriptInfo(fileName);
|
||||
return script.content;
|
||||
}
|
||||
|
||||
// Entry points from fourslash.ts
|
||||
public goToMarker(name = '') {
|
||||
var marker = this.getMarkerByName(name);
|
||||
@@ -376,8 +383,8 @@ module FourSlash {
|
||||
this.openFile(marker.fileName);
|
||||
}
|
||||
|
||||
var scriptSnapshot = this.languageServiceShimHost.getScriptSnapshot(marker.fileName);
|
||||
if (marker.position === -1 || marker.position > scriptSnapshot.getLength()) {
|
||||
var content = this.getFileContent(marker.fileName);
|
||||
if (marker.position === -1 || marker.position > content.length) {
|
||||
throw new Error('Marker "' + name + '" has been invalidated by unrecoverable edits to the file.');
|
||||
}
|
||||
this.lastKnownMarker = name;
|
||||
@@ -387,14 +394,14 @@ module FourSlash {
|
||||
public goToPosition(pos: number) {
|
||||
this.currentCaretPosition = pos;
|
||||
|
||||
var lineStarts = ts.computeLineStarts(this.getCurrentFileContent());
|
||||
var lineStarts = ts.computeLineStarts(this.getFileContent(this.activeFile.fileName));
|
||||
var lineCharPos = ts.computeLineAndCharacterOfPosition(lineStarts, pos);
|
||||
this.scenarioActions.push('<MoveCaretToLineAndChar LineNumber="' + lineCharPos.line + '" CharNumber="' + lineCharPos.character + '" />');
|
||||
}
|
||||
|
||||
public moveCaretRight(count = 1) {
|
||||
this.currentCaretPosition += count;
|
||||
this.currentCaretPosition = Math.min(this.currentCaretPosition, this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getLength());
|
||||
this.currentCaretPosition = Math.min(this.currentCaretPosition, this.getFileContent(this.activeFile.fileName).length);
|
||||
if (count > 0) {
|
||||
this.scenarioActions.push('<MoveCaretRight NumberOfChars="' + count + '" />');
|
||||
} else {
|
||||
@@ -453,7 +460,7 @@ module FourSlash {
|
||||
private getAllDiagnostics(): ts.Diagnostic[] {
|
||||
var diagnostics: ts.Diagnostic[] = [];
|
||||
|
||||
var fileNames = JSON.parse(this.languageServiceShimHost.getScriptFileNames());
|
||||
var fileNames = this.languageServiceAdapterHost.getFilenames();
|
||||
for (var i = 0, n = fileNames.length; i < n; i++) {
|
||||
diagnostics.push.apply(this.getDiagnostics(fileNames[i]));
|
||||
}
|
||||
@@ -805,7 +812,6 @@ module FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: { start: number; length: number; },
|
||||
displayParts: ts.SymbolDisplayPart[],
|
||||
documentation: ts.SymbolDisplayPart[]) {
|
||||
@@ -1211,8 +1217,7 @@ module FourSlash {
|
||||
var file = this.testData.files[i];
|
||||
var active = (this.activeFile === file);
|
||||
Harness.IO.log('=== Script (' + file.fileName + ') ' + (active ? '(active, cursor at |)' : '') + ' ===');
|
||||
var snapshot = this.languageServiceShimHost.getScriptSnapshot(file.fileName);
|
||||
var content = snapshot.getText(0, snapshot.getLength());
|
||||
var content = this.getFileContent(file.fileName);
|
||||
if (active) {
|
||||
content = content.substr(0, this.currentCaretPosition) + (makeCaretVisible ? '|' : "") + content.substr(this.currentCaretPosition);
|
||||
}
|
||||
@@ -1246,8 +1251,7 @@ module FourSlash {
|
||||
}
|
||||
|
||||
public printContext() {
|
||||
var fileNames: string[] = JSON.parse(this.languageServiceShimHost.getScriptFileNames());
|
||||
ts.forEach(fileNames, Harness.IO.log);
|
||||
ts.forEach(this.languageServiceAdapterHost.getFilenames(), Harness.IO.log);
|
||||
}
|
||||
|
||||
public deleteChar(count = 1) {
|
||||
@@ -1260,7 +1264,7 @@ module FourSlash {
|
||||
|
||||
for (var i = 0; i < count; i++) {
|
||||
// Make the edit
|
||||
this.languageServiceShimHost.editScript(this.activeFile.fileName, offset, offset + 1, ch);
|
||||
this.languageServiceAdapterHost.editScript(this.activeFile.fileName, offset, offset + 1, ch);
|
||||
this.updateMarkersForEdit(this.activeFile.fileName, offset, offset + 1, ch);
|
||||
|
||||
if (i % checkCadence === 0) {
|
||||
@@ -1287,7 +1291,7 @@ module FourSlash {
|
||||
public replace(start: number, length: number, text: string) {
|
||||
this.taoInvalidReason = 'replace NYI';
|
||||
|
||||
this.languageServiceShimHost.editScript(this.activeFile.fileName, start, start + length, text);
|
||||
this.languageServiceAdapterHost.editScript(this.activeFile.fileName, start, start + length, text);
|
||||
this.updateMarkersForEdit(this.activeFile.fileName, start, start + length, text);
|
||||
this.checkPostEditInvariants();
|
||||
}
|
||||
@@ -1302,7 +1306,7 @@ module FourSlash {
|
||||
for (var i = 0; i < count; i++) {
|
||||
offset--;
|
||||
// Make the edit
|
||||
this.languageServiceShimHost.editScript(this.activeFile.fileName, offset, offset + 1, ch);
|
||||
this.languageServiceAdapterHost.editScript(this.activeFile.fileName, offset, offset + 1, ch);
|
||||
this.updateMarkersForEdit(this.activeFile.fileName, offset, offset + 1, ch);
|
||||
|
||||
if (i % checkCadence === 0) {
|
||||
@@ -1347,7 +1351,7 @@ module FourSlash {
|
||||
for (var i = 0; i < text.length; i++) {
|
||||
// Make the edit
|
||||
var ch = text.charAt(i);
|
||||
this.languageServiceShimHost.editScript(this.activeFile.fileName, offset, offset, ch);
|
||||
this.languageServiceAdapterHost.editScript(this.activeFile.fileName, offset, offset, ch);
|
||||
this.languageService.getBraceMatchingAtPosition(this.activeFile.fileName, offset);
|
||||
|
||||
this.updateMarkersForEdit(this.activeFile.fileName, offset, offset, ch);
|
||||
@@ -1390,7 +1394,7 @@ module FourSlash {
|
||||
|
||||
var start = this.currentCaretPosition;
|
||||
var offset = this.currentCaretPosition;
|
||||
this.languageServiceShimHost.editScript(this.activeFile.fileName, offset, offset, text);
|
||||
this.languageServiceAdapterHost.editScript(this.activeFile.fileName, offset, offset, text);
|
||||
this.updateMarkersForEdit(this.activeFile.fileName, offset, offset, text);
|
||||
this.checkPostEditInvariants();
|
||||
offset += text.length;
|
||||
@@ -1412,14 +1416,19 @@ module FourSlash {
|
||||
}
|
||||
|
||||
private checkPostEditInvariants() {
|
||||
if (this.testType !== FourSlashTestType.Native) {
|
||||
// getSourcefile() results can not be serialized. Only perform these verifications
|
||||
// if running against a native LS object.
|
||||
return;
|
||||
}
|
||||
|
||||
var incrementalSourceFile = this.languageService.getSourceFile(this.activeFile.fileName);
|
||||
Utils.assertInvariants(incrementalSourceFile, /*parent:*/ undefined);
|
||||
|
||||
var incrementalSyntaxDiagnostics = incrementalSourceFile.parseDiagnostics;
|
||||
|
||||
// Check syntactic structure
|
||||
var snapshot = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName);
|
||||
var content = snapshot.getText(0, snapshot.getLength());
|
||||
var content = this.getFileContent(this.activeFile.fileName);
|
||||
|
||||
var referenceSourceFile = ts.createLanguageServiceSourceFile(
|
||||
this.activeFile.fileName, createScriptSnapShot(content), ts.ScriptTarget.Latest, /*version:*/ "0", /*setNodeParents:*/ false);
|
||||
@@ -1433,7 +1442,7 @@ module FourSlash {
|
||||
// The caret can potentially end up between the \r and \n, which is confusing. If
|
||||
// that happens, move it back one character
|
||||
if (this.currentCaretPosition > 0) {
|
||||
var ch = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(this.currentCaretPosition - 1, this.currentCaretPosition);
|
||||
var ch = this.getFileContent(this.activeFile.fileName).substring(this.currentCaretPosition - 1, this.currentCaretPosition);
|
||||
if (ch === '\r') {
|
||||
this.currentCaretPosition--;
|
||||
}
|
||||
@@ -1446,10 +1455,9 @@ module FourSlash {
|
||||
var runningOffset = 0;
|
||||
edits = edits.sort((a, b) => a.span.start - b.span.start);
|
||||
// Get a snapshot of the content of the file so we can make sure any formatting edits didn't destroy non-whitespace characters
|
||||
var snapshot = this.languageServiceShimHost.getScriptSnapshot(fileName);
|
||||
var oldContent = snapshot.getText(0, snapshot.getLength());
|
||||
var oldContent = this.getFileContent(this.activeFile.fileName);
|
||||
for (var j = 0; j < edits.length; j++) {
|
||||
this.languageServiceShimHost.editScript(fileName, edits[j].span.start + runningOffset, ts.textSpanEnd(edits[j].span) + runningOffset, edits[j].newText);
|
||||
this.languageServiceAdapterHost.editScript(fileName, edits[j].span.start + runningOffset, ts.textSpanEnd(edits[j].span) + runningOffset, edits[j].newText);
|
||||
this.updateMarkersForEdit(fileName, edits[j].span.start + runningOffset, ts.textSpanEnd(edits[j].span) + runningOffset, edits[j].newText);
|
||||
var change = (edits[j].span.start - ts.textSpanEnd(edits[j].span)) + edits[j].newText.length;
|
||||
runningOffset += change;
|
||||
@@ -1458,8 +1466,7 @@ module FourSlash {
|
||||
}
|
||||
|
||||
if (isFormattingEdit) {
|
||||
snapshot = this.languageServiceShimHost.getScriptSnapshot(fileName);
|
||||
var newContent = snapshot.getText(0, snapshot.getLength());
|
||||
var newContent = this.getFileContent(fileName);
|
||||
|
||||
if (newContent.replace(/\s/g, '') !== oldContent.replace(/\s/g, '')) {
|
||||
this.raiseError('Formatting operation destroyed non-whitespace content');
|
||||
@@ -1506,7 +1513,7 @@ module FourSlash {
|
||||
}
|
||||
|
||||
public goToEOF() {
|
||||
var len = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getLength();
|
||||
var len = this.getFileContent(this.activeFile.fileName).length;
|
||||
this.goToPosition(len);
|
||||
}
|
||||
|
||||
@@ -1627,7 +1634,7 @@ module FourSlash {
|
||||
public verifyCurrentFileContent(text: string) {
|
||||
this.taoInvalidReason = 'verifyCurrentFileContent NYI';
|
||||
|
||||
var actual = this.getCurrentFileContent();
|
||||
var actual = this.getFileContent(this.activeFile.fileName);
|
||||
var replaceNewlines = (str: string) => str.replace(/\r\n/g, "\n");
|
||||
if (replaceNewlines(actual) !== replaceNewlines(text)) {
|
||||
throw new Error('verifyCurrentFileContent\n' +
|
||||
@@ -1639,7 +1646,7 @@ module FourSlash {
|
||||
public verifyTextAtCaretIs(text: string) {
|
||||
this.taoInvalidReason = 'verifyCurrentFileContent NYI';
|
||||
|
||||
var actual = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(this.currentCaretPosition, this.currentCaretPosition + text.length);
|
||||
var actual = this.getFileContent(this.activeFile.fileName).substring(this.currentCaretPosition, this.currentCaretPosition + text.length);
|
||||
if (actual !== text) {
|
||||
throw new Error('verifyTextAtCaretIs\n' +
|
||||
'\tExpected: "' + text + '"\n' +
|
||||
@@ -1657,7 +1664,7 @@ module FourSlash {
|
||||
'\t Actual: undefined');
|
||||
}
|
||||
|
||||
var actual = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(span.start, ts.textSpanEnd(span));
|
||||
var actual = this.getFileContent(this.activeFile.fileName).substring(span.start, ts.textSpanEnd(span));
|
||||
if (actual !== text) {
|
||||
this.raiseError('verifyCurrentNameOrDottedNameSpanText\n' +
|
||||
'\tExpected: "' + text + '"\n' +
|
||||
@@ -1731,8 +1738,8 @@ module FourSlash {
|
||||
|
||||
function jsonMismatchString() {
|
||||
return ts.sys.newLine +
|
||||
"expected: '" + ts.sys.newLine + JSON.stringify(expected,(k, v) => v, 2) + "'" + ts.sys.newLine +
|
||||
"actual: '" + ts.sys.newLine + JSON.stringify(actual,(k, v) => v, 2) + "'";
|
||||
"expected: '" + ts.sys.newLine + JSON.stringify(expected, (k, v) => v, 2) + "'" + ts.sys.newLine +
|
||||
"actual: '" + ts.sys.newLine + JSON.stringify(actual, (k, v) => v, 2) + "'";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1744,7 +1751,7 @@ module FourSlash {
|
||||
}
|
||||
|
||||
public verifySyntacticClassifications(expected: { classificationType: string; text: string }[]) {
|
||||
var actual = this.languageService.getSyntacticClassifications(this.activeFile.fileName,
|
||||
var actual = this.languageService.getSyntacticClassifications(this.activeFile.fileName,
|
||||
ts.createTextSpan(0, this.activeFile.content.length));
|
||||
|
||||
this.verifyClassifications(expected, actual);
|
||||
@@ -1820,69 +1827,6 @@ module FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public verifyTypesAgainstFullCheckAtPositions(positions: number[]) {
|
||||
this.taoInvalidReason = 'verifyTypesAgainstFullCheckAtPositions impossible';
|
||||
|
||||
// Create a from-scratch LS to check against
|
||||
var referenceLanguageServiceShimHost = new Harness.LanguageService.TypeScriptLS();
|
||||
var referenceLanguageServiceShim = referenceLanguageServiceShimHost.getLanguageService();
|
||||
var referenceLanguageService = referenceLanguageServiceShim.languageService;
|
||||
|
||||
// Add lib.d.ts to the reference language service
|
||||
referenceLanguageServiceShimHost.addDefaultLibrary();
|
||||
|
||||
for (var i = 0; i < this.testData.files.length; i++) {
|
||||
var file = this.testData.files[i];
|
||||
|
||||
var snapshot = this.languageServiceShimHost.getScriptSnapshot(file.fileName);
|
||||
var content = snapshot.getText(0, snapshot.getLength());
|
||||
referenceLanguageServiceShimHost.addScript(this.testData.files[i].fileName, content);
|
||||
}
|
||||
|
||||
for (i = 0; i < positions.length; i++) {
|
||||
var nameOf = (type: ts.QuickInfo) => type ? ts.displayPartsToString(type.displayParts) : '(none)';
|
||||
|
||||
var pullName: string, refName: string;
|
||||
var anyFailed = false;
|
||||
|
||||
var errMsg = '';
|
||||
|
||||
try {
|
||||
var pullType = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, positions[i]);
|
||||
pullName = nameOf(pullType);
|
||||
} catch (err1) {
|
||||
errMsg = 'Failed to get pull type check. Exception: ' + err1 + '\r\n';
|
||||
if (err1.stack) errMsg = errMsg + err1.stack;
|
||||
pullName = '(failed)';
|
||||
anyFailed = true;
|
||||
}
|
||||
|
||||
try {
|
||||
var referenceType = referenceLanguageService.getQuickInfoAtPosition(this.activeFile.fileName, positions[i]);
|
||||
refName = nameOf(referenceType);
|
||||
} catch (err2) {
|
||||
errMsg = 'Failed to get full type check. Exception: ' + err2 + '\r\n';
|
||||
if (err2.stack) errMsg = errMsg + err2.stack;
|
||||
refName = '(failed)';
|
||||
anyFailed = true;
|
||||
}
|
||||
|
||||
var failure = anyFailed || (refName !== pullName);
|
||||
if (failure) {
|
||||
snapshot = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName);
|
||||
content = snapshot.getText(0, snapshot.getLength());
|
||||
var textAtPosition = content.substr(positions[i], 10);
|
||||
var positionDescription = 'Position ' + positions[i] + ' ("' + textAtPosition + '"...)';
|
||||
|
||||
if (anyFailed) {
|
||||
throw new Error('Exception thrown in language service for ' + positionDescription + '\r\n' + errMsg);
|
||||
} else if (refName !== pullName) {
|
||||
throw new Error('Pull/Full disagreement failed at ' + positionDescription + ' - expected full typecheck type "' + refName + '" to equal pull type "' + pullName + '".');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Check number of navigationItems which match both searchValue and matchKind.
|
||||
Report an error if expected value and actual value do not match.
|
||||
@@ -2069,12 +2013,11 @@ module FourSlash {
|
||||
// The current caret position (in line/col terms)
|
||||
var line = this.getCurrentCaretFilePosition().line;
|
||||
// The line/col of the start of this line
|
||||
var pos = this.languageServiceShimHost.lineColToPosition(this.activeFile.fileName, line, 1);
|
||||
var pos = this.languageServiceAdapterHost.lineColToPosition(this.activeFile.fileName, line, 1);
|
||||
// The index of the current file
|
||||
|
||||
// The text from the start of the line to the end of the file
|
||||
var snapshot = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName);
|
||||
var text = snapshot.getText(pos, snapshot.getLength());
|
||||
var text = this.getFileContent(this.activeFile.fileName).substring(pos);
|
||||
|
||||
// Truncate to the first newline
|
||||
var newlinePos = text.indexOf('\n');
|
||||
@@ -2089,13 +2032,8 @@ module FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
private getCurrentFileContent() {
|
||||
var snapshot = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName);
|
||||
return snapshot.getText(0, snapshot.getLength());
|
||||
}
|
||||
|
||||
private getCurrentCaretFilePosition() {
|
||||
var result = this.languageServiceShimHost.positionToZeroBasedLineCol(this.activeFile.fileName, this.currentCaretPosition);
|
||||
var result = this.languageServiceAdapterHost.positionToZeroBasedLineCol(this.activeFile.fileName, this.currentCaretPosition);
|
||||
if (result.line >= 0) {
|
||||
result.line++;
|
||||
}
|
||||
@@ -2153,8 +2091,10 @@ module FourSlash {
|
||||
}
|
||||
} else if (typeof indexOrName === 'string') {
|
||||
var name = <string>indexOrName;
|
||||
|
||||
// names are stored in the compiler with this relative path, this allows people to use goTo.file on just the fileName
|
||||
name = name.indexOf('/') === -1 ? 'tests/cases/fourslash/' + name : name;
|
||||
name = name.indexOf('/') === -1 ? (this.basePath + '/' + name) : name;
|
||||
|
||||
var availableNames: string[] = [];
|
||||
var foundIt = false;
|
||||
for (var i = 0; i < this.testData.files.length; i++) {
|
||||
@@ -2180,7 +2120,7 @@ module FourSlash {
|
||||
}
|
||||
|
||||
private getLineColStringAtPosition(position: number) {
|
||||
var pos = this.languageServiceShimHost.positionToZeroBasedLineCol(this.activeFile.fileName, position);
|
||||
var pos = this.languageServiceAdapterHost.positionToZeroBasedLineCol(this.activeFile.fileName, position);
|
||||
return 'line ' + (pos.line + 1) + ', col ' + pos.character;
|
||||
}
|
||||
|
||||
@@ -2206,23 +2146,31 @@ module FourSlash {
|
||||
originalName: ''
|
||||
};
|
||||
}
|
||||
|
||||
public setCancelled(numberOfCalls: number): void {
|
||||
this.cancellationToken.setCancelled(numberOfCalls)
|
||||
}
|
||||
|
||||
public resetCancelled(): void {
|
||||
this.cancellationToken.resetCancelled();
|
||||
}
|
||||
}
|
||||
|
||||
// TOOD: should these just use the Harness's stdout/stderr?
|
||||
var fsOutput = new Harness.Compiler.WriterAggregator();
|
||||
var fsErrors = new Harness.Compiler.WriterAggregator();
|
||||
export var xmlData: TestXmlData[] = [];
|
||||
export function runFourSlashTest(fileName: string) {
|
||||
export function runFourSlashTest(basePath: string, testType: FourSlashTestType, fileName: string) {
|
||||
var content = Harness.IO.readFile(fileName);
|
||||
var xml = runFourSlashTestContent(content, fileName);
|
||||
var xml = runFourSlashTestContent(basePath, testType, content, fileName);
|
||||
xmlData.push(xml);
|
||||
}
|
||||
|
||||
export function runFourSlashTestContent(content: string, fileName: string): TestXmlData {
|
||||
export function runFourSlashTestContent(basePath: string, testType: FourSlashTestType, content: string, fileName: string): TestXmlData {
|
||||
// Parse out the files and their metadata
|
||||
var testData = parseTestData(content, fileName);
|
||||
var testData = parseTestData(basePath, content, fileName);
|
||||
|
||||
currentTestState = new TestState(testData);
|
||||
currentTestState = new TestState(basePath, testType, testData);
|
||||
|
||||
var result = '';
|
||||
var host = Harness.Compiler.createCompilerHost([{ unitName: Harness.Compiler.fourslashFileName, content: undefined },
|
||||
@@ -2265,7 +2213,7 @@ module FourSlash {
|
||||
return lines.map(s => s.substr(1)).join('\n');
|
||||
}
|
||||
|
||||
function parseTestData(contents: string, fileName: string): FourSlashData {
|
||||
function parseTestData(basePath: string, contents: string, fileName: string): FourSlashData {
|
||||
// Regex for parsing options in the format "@Alpha: Value of any sort"
|
||||
var optionRegex = /^\s*@(\w+): (.*)\s*/;
|
||||
|
||||
@@ -2333,7 +2281,7 @@ module FourSlash {
|
||||
currentFileName = fileName;
|
||||
}
|
||||
|
||||
currentFileName = 'tests/cases/fourslash/' + match[2];
|
||||
currentFileName = basePath + '/' + match[2];
|
||||
currentFileOptions[match[1]] = match[2];
|
||||
} else {
|
||||
// Add other fileMetadata flag
|
||||
|
||||
@@ -2,19 +2,35 @@
|
||||
///<reference path='harness.ts'/>
|
||||
///<reference path='runnerbase.ts' />
|
||||
|
||||
class FourslashRunner extends RunnerBase {
|
||||
public basePath = 'tests/cases/fourslash';
|
||||
const enum FourSlashTestType {
|
||||
Native,
|
||||
Shims
|
||||
}
|
||||
|
||||
constructor() {
|
||||
class FourSlashRunner extends RunnerBase {
|
||||
protected basePath: string;
|
||||
protected testSuiteName: string;
|
||||
|
||||
constructor(private testType: FourSlashTestType) {
|
||||
super();
|
||||
switch (testType) {
|
||||
case FourSlashTestType.Native:
|
||||
this.basePath = 'tests/cases/fourslash';
|
||||
this.testSuiteName = 'fourslash';
|
||||
break;
|
||||
case FourSlashTestType.Shims:
|
||||
this.basePath = 'tests/cases/fourslash/shims';
|
||||
this.testSuiteName = 'fourslash-shims';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public initializeTests() {
|
||||
if (this.tests.length === 0) {
|
||||
this.tests = this.enumerateFiles(this.basePath, /\.ts/i);
|
||||
this.tests = this.enumerateFiles(this.basePath, /\.ts/i, { recursive: false });
|
||||
}
|
||||
|
||||
describe("fourslash tests", () => {
|
||||
describe(this.testSuiteName, () => {
|
||||
this.tests.forEach((fn: string) => {
|
||||
fn = ts.normalizeSlashes(fn);
|
||||
var justName = fn.replace(/^.*[\\\/]/, '');
|
||||
@@ -24,8 +40,8 @@ class FourslashRunner extends RunnerBase {
|
||||
if (testIndex >= 0) fn = fn.substr(testIndex);
|
||||
|
||||
if (justName && !justName.match(/fourslash\.ts$/i) && !justName.match(/\.d\.ts$/i)) {
|
||||
it('FourSlash test ' + justName + ' runs correctly', function () {
|
||||
FourSlash.runFourSlashTest(fn);
|
||||
it(this.testSuiteName + ' test ' + justName + ' runs correctly',() => {
|
||||
FourSlash.runFourSlashTest(this.basePath, this.testType, fn);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -82,9 +98,9 @@ class FourslashRunner extends RunnerBase {
|
||||
}
|
||||
}
|
||||
|
||||
class GeneratedFourslashRunner extends FourslashRunner {
|
||||
constructor() {
|
||||
super();
|
||||
class GeneratedFourslashRunner extends FourSlashRunner {
|
||||
constructor(testType: FourSlashTestType) {
|
||||
super(testType);
|
||||
this.basePath += '/generated/';
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@
|
||||
/// <reference path='external\mocha.d.ts'/>
|
||||
/// <reference path='external\chai.d.ts'/>
|
||||
/// <reference path='sourceMapRecorder.ts'/>
|
||||
/// <reference path='runnerbase.ts'/>
|
||||
|
||||
declare var require: any;
|
||||
declare var process: any;
|
||||
@@ -691,8 +692,6 @@ module Harness {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
module Harness {
|
||||
var tcServicesFileName = "typescriptServices.js";
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/// <reference path='..\services\services.ts' />
|
||||
/// <reference path='..\services\shims.ts' />
|
||||
/// <reference path='harness.ts' />
|
||||
|
||||
module Harness.LanguageService {
|
||||
export class ScriptInfo {
|
||||
@@ -54,12 +55,11 @@ module Harness.LanguageService {
|
||||
}
|
||||
}
|
||||
|
||||
class ScriptSnapshotShim implements ts.ScriptSnapshotShim {
|
||||
private lineMap: number[] = null;
|
||||
private textSnapshot: string;
|
||||
private version: number;
|
||||
class ScriptSnapshot implements ts.IScriptSnapshot {
|
||||
public textSnapshot: string;
|
||||
public version: number;
|
||||
|
||||
constructor(private scriptInfo: ScriptInfo) {
|
||||
constructor(public scriptInfo: ScriptInfo) {
|
||||
this.textSnapshot = scriptInfo.content;
|
||||
this.version = scriptInfo.version;
|
||||
}
|
||||
@@ -72,9 +72,28 @@ module Harness.LanguageService {
|
||||
return this.textSnapshot.length;
|
||||
}
|
||||
|
||||
public getChangeRange(oldScript: ts.IScriptSnapshot): ts.TextChangeRange {
|
||||
var oldShim = <ScriptSnapshot>oldScript;
|
||||
return this.scriptInfo.getTextChangeRangeBetweenVersions(oldShim.version, this.version);
|
||||
}
|
||||
}
|
||||
|
||||
class ScriptSnapshotProxy implements ts.ScriptSnapshotShim {
|
||||
constructor(public scriptSnapshot: ts.IScriptSnapshot) {
|
||||
}
|
||||
|
||||
public getText(start: number, end: number): string {
|
||||
return this.scriptSnapshot.getText(start, end);
|
||||
}
|
||||
|
||||
public getLength(): number {
|
||||
return this.scriptSnapshot.getLength();
|
||||
}
|
||||
|
||||
public getChangeRange(oldScript: ts.ScriptSnapshotShim): string {
|
||||
var oldShim = <ScriptSnapshotShim>oldScript;
|
||||
var range = this.scriptInfo.getTextChangeRangeBetweenVersions(oldShim.version, this.version);
|
||||
var oldShim = <ScriptSnapshotProxy>oldScript;
|
||||
|
||||
var range = this.scriptSnapshot.getChangeRange(oldShim.scriptSnapshot);
|
||||
if (range === null) {
|
||||
return null;
|
||||
}
|
||||
@@ -94,77 +113,38 @@ module Harness.LanguageService {
|
||||
}
|
||||
}
|
||||
|
||||
export class NonCachingDocumentRegistry implements ts.DocumentRegistry {
|
||||
public static Instance: ts.DocumentRegistry = new NonCachingDocumentRegistry();
|
||||
|
||||
public acquireDocument(
|
||||
fileName: string,
|
||||
compilationSettings: ts.CompilerOptions,
|
||||
scriptSnapshot: ts.IScriptSnapshot,
|
||||
version: string): ts.SourceFile {
|
||||
var sourceFile = Compiler.createSourceFileAndAssertInvariants(fileName, scriptSnapshot.getText(0, scriptSnapshot.getLength()), compilationSettings.target);
|
||||
sourceFile.version = version;
|
||||
return sourceFile;
|
||||
}
|
||||
|
||||
public updateDocument(
|
||||
document: ts.SourceFile,
|
||||
fileName: string,
|
||||
compilationSettings: ts.CompilerOptions,
|
||||
scriptSnapshot: ts.IScriptSnapshot,
|
||||
version: string,
|
||||
textChangeRange: ts.TextChangeRange
|
||||
): ts.SourceFile {
|
||||
var result = ts.updateLanguageServiceSourceFile(document, scriptSnapshot, version, textChangeRange);
|
||||
Utils.assertInvariants(result, /*parent:*/ undefined);
|
||||
return result;
|
||||
}
|
||||
|
||||
public releaseDocument(fileName: string, compilationSettings: ts.CompilerOptions): void {
|
||||
// no op since this class doesn't cache anything
|
||||
}
|
||||
export interface LanguageServiceAdapter {
|
||||
getHost(): LanguageServiceAdapterHost;
|
||||
getLanguageService(): ts.LanguageService;
|
||||
getClassifier(): ts.Classifier;
|
||||
getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo;
|
||||
}
|
||||
export class TypeScriptLS implements ts.LanguageServiceShimHost {
|
||||
private ls: ts.LanguageServiceShim = null;
|
||||
|
||||
private fileNameToScript: ts.Map<ScriptInfo> = {};
|
||||
private settings: ts.CompilerOptions = {};
|
||||
|
||||
constructor(private cancellationToken: ts.CancellationToken = CancellationToken.None) {
|
||||
}
|
||||
|
||||
public trace(s: string) {
|
||||
export class LanguageServiceAdapterHost {
|
||||
protected fileNameToScript: ts.Map<ScriptInfo> = {};
|
||||
|
||||
constructor(protected cancellationToken: ts.CancellationToken = CancellationToken.None,
|
||||
protected settings = ts.getDefaultCompilerOptions()) {
|
||||
}
|
||||
|
||||
public getNewLine(): string {
|
||||
return "\r\n";
|
||||
}
|
||||
|
||||
public addDefaultLibrary() {
|
||||
this.addScript(Harness.Compiler.defaultLibFileName, Harness.Compiler.defaultLibSourceFile.text);
|
||||
public getFilenames(): string[] {
|
||||
var fileNames: string[] = [];
|
||||
ts.forEachKey(this.fileNameToScript,(fileName) => { fileNames.push(fileName); });
|
||||
return fileNames;
|
||||
}
|
||||
|
||||
public getHostIdentifier(): string {
|
||||
return "TypeScriptLS";
|
||||
}
|
||||
|
||||
public addFile(fileName: string) {
|
||||
var code = Harness.IO.readFile(fileName);
|
||||
this.addScript(fileName, code);
|
||||
}
|
||||
|
||||
private getScriptInfo(fileName: string): ScriptInfo {
|
||||
public getScriptInfo(fileName: string): ScriptInfo {
|
||||
return ts.lookUp(this.fileNameToScript, fileName);
|
||||
}
|
||||
|
||||
public addScript(fileName: string, content: string) {
|
||||
public addScript(fileName: string, content: string): void {
|
||||
this.fileNameToScript[fileName] = new ScriptInfo(fileName, content);
|
||||
}
|
||||
|
||||
private contains(fileName: string): boolean {
|
||||
return ts.hasProperty(this.fileNameToScript, fileName);
|
||||
}
|
||||
|
||||
public updateScript(fileName: string, content: string) {
|
||||
var script = this.getScriptInfo(fileName);
|
||||
if (script !== null) {
|
||||
@@ -185,107 +165,10 @@ module Harness.LanguageService {
|
||||
throw new Error("No script with name '" + fileName + "'");
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// ILogger implementation
|
||||
//
|
||||
public information(): boolean { return false; }
|
||||
public debug(): boolean { return true; }
|
||||
public warning(): boolean { return true; }
|
||||
public error(): boolean { return true; }
|
||||
public fatal(): boolean { return true; }
|
||||
|
||||
public log(s: string): void {
|
||||
// For debugging...
|
||||
//TypeScript.Environment.standardOut.WriteLine("TypeScriptLS:" + s);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// LanguageServiceShimHost implementation
|
||||
//
|
||||
|
||||
/// Returns json for Tools.CompilationSettings
|
||||
public getCompilationSettings(): string {
|
||||
return JSON.stringify(this.settings);
|
||||
}
|
||||
|
||||
public getCancellationToken(): ts.CancellationToken {
|
||||
return this.cancellationToken;
|
||||
}
|
||||
|
||||
public getCurrentDirectory(): string {
|
||||
return "";
|
||||
}
|
||||
|
||||
public getDefaultLibFileName(): string {
|
||||
return "";
|
||||
}
|
||||
|
||||
public getScriptFileNames(): string {
|
||||
var fileNames: string[] = [];
|
||||
ts.forEachKey(this.fileNameToScript,(fileName) => { fileNames.push(fileName); });
|
||||
return JSON.stringify(fileNames);
|
||||
}
|
||||
|
||||
public getScriptSnapshot(fileName: string): ts.ScriptSnapshotShim {
|
||||
if (this.contains(fileName)) {
|
||||
return new ScriptSnapshotShim(this.getScriptInfo(fileName));
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public getScriptVersion(fileName: string): string {
|
||||
if (this.contains(fileName)) {
|
||||
return this.getScriptInfo(fileName).version.toString();
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public getLocalizedDiagnosticMessages(): string {
|
||||
return JSON.stringify({});
|
||||
}
|
||||
|
||||
/** Return a new instance of the language service shim, up-to-date wrt to typecheck.
|
||||
* To access the non-shim (i.e. actual) language service, use the "ls.languageService" property.
|
||||
*/
|
||||
public getLanguageService(): ts.LanguageServiceShim {
|
||||
this.ls = new TypeScript.Services.TypeScriptServicesFactory().createLanguageServiceShim(this);
|
||||
return this.ls;
|
||||
}
|
||||
|
||||
public setCompilationSettings(settings: ts.CompilerOptions) {
|
||||
for (var key in settings) {
|
||||
if (settings.hasOwnProperty(key)) {
|
||||
this.settings[key] = settings[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Return a new instance of the classifier service shim */
|
||||
public getClassifier(): ts.ClassifierShim {
|
||||
return new TypeScript.Services.TypeScriptServicesFactory().createClassifierShim(this);
|
||||
}
|
||||
|
||||
public getCoreService(): ts.CoreServicesShim {
|
||||
return new TypeScript.Services.TypeScriptServicesFactory().createCoreServicesShim(this);
|
||||
}
|
||||
|
||||
/** Parse file given its source text */
|
||||
public parseSourceText(fileName: string, sourceText: ts.IScriptSnapshot): ts.SourceFile {
|
||||
var result = Compiler.createSourceFileAndAssertInvariants(fileName, sourceText.getText(0, sourceText.getLength()), ts.ScriptTarget.Latest);
|
||||
result.version = "1";
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Parse a file on disk given its fileName */
|
||||
public parseFile(fileName: string) {
|
||||
var sourceText = ts.ScriptSnapshot.fromString(Harness.IO.readFile(fileName));
|
||||
return this.parseSourceText(fileName, sourceText);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param line 1 based index
|
||||
* @param col 1 based index
|
||||
*/
|
||||
* @param line 1 based index
|
||||
* @param col 1 based index
|
||||
*/
|
||||
public lineColToPosition(fileName: string, line: number, col: number): number {
|
||||
var script: ScriptInfo = this.fileNameToScript[fileName];
|
||||
assert.isNotNull(script);
|
||||
@@ -296,9 +179,9 @@ module Harness.LanguageService {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param line 0 based index
|
||||
* @param col 0 based index
|
||||
*/
|
||||
* @param line 0 based index
|
||||
* @param col 0 based index
|
||||
*/
|
||||
public positionToZeroBasedLineCol(fileName: string, position: number): ts.LineAndCharacter {
|
||||
var script: ScriptInfo = this.fileNameToScript[fileName];
|
||||
assert.isNotNull(script);
|
||||
@@ -309,105 +192,254 @@ module Harness.LanguageService {
|
||||
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 */
|
||||
public checkEdits(sourceFileName: string, baselineFileName: string, edits: ts.TextChange[]) {
|
||||
var script = Harness.IO.readFile(sourceFileName);
|
||||
var formattedScript = this.applyEdits(script, edits);
|
||||
var baseline = Harness.IO.readFile(baselineFileName);
|
||||
/// Native adapter
|
||||
class NativeLanguageServiceHost extends LanguageServiceAdapterHost implements ts.LanguageServiceHost {
|
||||
getCompilationSettings(): ts.CompilerOptions { return this.settings; }
|
||||
getCancellationToken(): ts.CancellationToken { return this.cancellationToken; }
|
||||
getCurrentDirectory(): string { return ""; }
|
||||
getDefaultLibFileName(): string { return ""; }
|
||||
getScriptFileNames(): string[] { return this.getFilenames(); }
|
||||
getScriptSnapshot(fileName: string): ts.IScriptSnapshot {
|
||||
var script = this.getScriptInfo(fileName);
|
||||
return script ? new ScriptSnapshot(script) : undefined;
|
||||
}
|
||||
getScriptVersion(fileName: string): string {
|
||||
var script = this.getScriptInfo(fileName);
|
||||
return script ? script.version.toString() : undefined;
|
||||
}
|
||||
log(s: string): void { }
|
||||
trace(s: string): void { }
|
||||
error(s: string): void { }
|
||||
}
|
||||
|
||||
function noDiff(text1: string, text2: string) {
|
||||
text1 = text1.replace(/^\s+|\s+$/g, "").replace(/\r\n?/g, "\n");
|
||||
text2 = text2.replace(/^\s+|\s+$/g, "").replace(/\r\n?/g, "\n");
|
||||
export class NativeLanugageServiceAdapter implements LanguageServiceAdapter {
|
||||
private host: NativeLanguageServiceHost;
|
||||
constructor(cancellationToken?: ts.CancellationToken, options?: ts.CompilerOptions) {
|
||||
this.host = new NativeLanguageServiceHost(cancellationToken, options);
|
||||
}
|
||||
getHost() { return this.host; }
|
||||
getLanguageService(): ts.LanguageService { return ts.createLanguageService(this.host); }
|
||||
getClassifier(): ts.Classifier { return ts.createClassifier(); }
|
||||
getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { return ts.preProcessFile(fileContents); }
|
||||
}
|
||||
|
||||
if (text1 !== text2) {
|
||||
var errorString = "";
|
||||
var text1Lines = text1.split(/\n/);
|
||||
var text2Lines = text2.split(/\n/);
|
||||
for (var i = 0; i < text1Lines.length; i++) {
|
||||
if (text1Lines[i] !== text2Lines[i]) {
|
||||
errorString += "Difference at line " + (i + 1) + ":\n";
|
||||
errorString += " Left File: " + text1Lines[i] + "\n";
|
||||
errorString += " Right File: " + text2Lines[i] + "\n\n";
|
||||
}
|
||||
}
|
||||
throw (new Error(errorString));
|
||||
}
|
||||
}
|
||||
assert.isTrue(noDiff(formattedScript, baseline));
|
||||
assert.equal(formattedScript, baseline);
|
||||
/// Shim adapter
|
||||
class ShimLanguageServiceHost extends LanguageServiceAdapterHost implements ts.LanguageServiceShimHost {
|
||||
private nativeHost: NativeLanguageServiceHost;
|
||||
constructor(cancellationToken?: ts.CancellationToken, options?: ts.CompilerOptions) {
|
||||
super(cancellationToken, options);
|
||||
this.nativeHost = new NativeLanguageServiceHost(cancellationToken, options);
|
||||
}
|
||||
|
||||
getFilenames(): string[] { return this.nativeHost.getFilenames(); }
|
||||
getScriptInfo(fileName: string): ScriptInfo { return this.nativeHost.getScriptInfo(fileName); }
|
||||
addScript(fileName: string, content: string): void { this.nativeHost.addScript(fileName, content); }
|
||||
updateScript(fileName: string, content: string): void { return this.nativeHost.updateScript(fileName, content); }
|
||||
editScript(fileName: string, minChar: number, limChar: number, newText: string): void { this.nativeHost.editScript(fileName, minChar, limChar, newText); }
|
||||
lineColToPosition(fileName: string, line: number, col: number): number { return this.nativeHost.lineColToPosition(fileName, line, col); }
|
||||
positionToZeroBasedLineCol(fileName: string, position: number): ts.LineAndCharacter { return this.nativeHost.positionToZeroBasedLineCol(fileName, position); }
|
||||
|
||||
/** Apply an array of text edits to a string, and return the resulting string. */
|
||||
public applyEdits(content: string, edits: ts.TextChange[]): string {
|
||||
var result = content;
|
||||
edits = this.normalizeEdits(edits);
|
||||
|
||||
for (var i = edits.length - 1; i >= 0; i--) {
|
||||
var edit = edits[i];
|
||||
var prefix = result.substring(0, edit.span.start);
|
||||
var middle = edit.newText;
|
||||
var suffix = result.substring(ts.textSpanEnd(edit.span));
|
||||
result = prefix + middle + suffix;
|
||||
}
|
||||
return result;
|
||||
getCompilationSettings(): string { return JSON.stringify(this.nativeHost.getCompilationSettings()); }
|
||||
getCancellationToken(): ts.CancellationToken { return this.nativeHost.getCancellationToken(); }
|
||||
getCurrentDirectory(): string { return this.nativeHost.getCurrentDirectory(); }
|
||||
getDefaultLibFileName(): string { return this.nativeHost.getDefaultLibFileName(); }
|
||||
getScriptFileNames(): string { return JSON.stringify(this.nativeHost.getScriptFileNames()); }
|
||||
getScriptSnapshot(fileName: string): ts.ScriptSnapshotShim {
|
||||
var nativeScriptSnapshot = this.nativeHost.getScriptSnapshot(fileName);
|
||||
return nativeScriptSnapshot && new ScriptSnapshotProxy(nativeScriptSnapshot);
|
||||
}
|
||||
getScriptVersion(fileName: string): string { return this.nativeHost.getScriptVersion(fileName); }
|
||||
getLocalizedDiagnosticMessages(): string { return JSON.stringify({}); }
|
||||
log(s: string): void { this.nativeHost.log(s); }
|
||||
trace(s: string): void { this.nativeHost.trace(s); }
|
||||
error(s: string): void { this.nativeHost.error(s); }
|
||||
}
|
||||
|
||||
/** Normalize an array of edits by removing overlapping entries and sorting entries on the minChar position. */
|
||||
private normalizeEdits(edits: ts.TextChange[]): ts.TextChange[] {
|
||||
var result: ts.TextChange[] = [];
|
||||
class ClassifierShimProxy implements ts.Classifier {
|
||||
constructor(private shim: ts.ClassifierShim) {
|
||||
}
|
||||
getClassificationsForLine(text: string, lexState: ts.EndOfLineState, classifyKeywordsInGenerics?: boolean): ts.ClassificationResult {
|
||||
var result = this.shim.getClassificationsForLine(text, lexState, classifyKeywordsInGenerics).split('\n');
|
||||
var entries: ts.ClassificationInfo[] = [];
|
||||
var i = 0;
|
||||
var position = 0;
|
||||
|
||||
function mapEdits(edits: ts.TextChange[]): { edit: ts.TextChange; index: number; }[] {
|
||||
var result: { edit: ts.TextChange; index: number; }[] = [];
|
||||
for (var i = 0; i < edits.length; i++) {
|
||||
result.push({ edit: edits[i], index: i });
|
||||
}
|
||||
return result;
|
||||
for (; i < result.length - 1; i += 2) {
|
||||
var t = entries[i / 2] = {
|
||||
length: parseInt(result[i]),
|
||||
classification: parseInt(result[i + 1])
|
||||
};
|
||||
|
||||
assert.isTrue(t.length > 0, "Result length should be greater than 0, got :" + t.length);
|
||||
position += t.length;
|
||||
}
|
||||
var finalLexState = parseInt(result[result.length - 1]);
|
||||
|
||||
var temp = mapEdits(edits).sort(function (a, b) {
|
||||
var result = a.edit.span.start - b.edit.span.start;
|
||||
if (result === 0)
|
||||
result = a.index - b.index;
|
||||
return result;
|
||||
assert.equal(position, text.length, "Expected cumulative length of all entries to match the length of the source. expected: " + text.length + ", but got: " + position);
|
||||
|
||||
return {
|
||||
finalLexState,
|
||||
entries
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function unwrapJSONCallResult(result: string): any {
|
||||
var parsedResult = JSON.parse(result);
|
||||
if (parsedResult.error) {
|
||||
throw new Error("Language Service Shim Error: " + JSON.stringify(parsedResult.error));
|
||||
}
|
||||
else if (parsedResult.canceled) {
|
||||
throw new ts.OperationCanceledException();
|
||||
}
|
||||
return parsedResult.result;
|
||||
}
|
||||
|
||||
class LanguageServiceShimProxy implements ts.LanguageService {
|
||||
constructor(private shim: ts.LanguageServiceShim) {
|
||||
}
|
||||
private unwrappJSONCallResult(result: string): any {
|
||||
var parsedResult = JSON.parse(result);
|
||||
if (parsedResult.error) {
|
||||
throw new Error("Language Service Shim Error: " + JSON.stringify(parsedResult.error));
|
||||
}
|
||||
return parsedResult.result;
|
||||
}
|
||||
cleanupSemanticCache(): void {
|
||||
this.shim.cleanupSemanticCache();
|
||||
}
|
||||
getSyntacticDiagnostics(fileName: string): ts.Diagnostic[] {
|
||||
return unwrapJSONCallResult(this.shim.getSyntacticDiagnostics(fileName));
|
||||
}
|
||||
getSemanticDiagnostics(fileName: string): ts.Diagnostic[] {
|
||||
return unwrapJSONCallResult(this.shim.getSemanticDiagnostics(fileName));
|
||||
}
|
||||
getCompilerOptionsDiagnostics(): ts.Diagnostic[] {
|
||||
return unwrapJSONCallResult(this.shim.getCompilerOptionsDiagnostics());
|
||||
}
|
||||
getSyntacticClassifications(fileName: string, span: ts.TextSpan): ts.ClassifiedSpan[] {
|
||||
return unwrapJSONCallResult(this.shim.getSyntacticClassifications(fileName, span.start, span.length));
|
||||
}
|
||||
getSemanticClassifications(fileName: string, span: ts.TextSpan): ts.ClassifiedSpan[] {
|
||||
return unwrapJSONCallResult(this.shim.getSemanticClassifications(fileName, span.start, span.length));
|
||||
}
|
||||
getCompletionsAtPosition(fileName: string, position: number): ts.CompletionInfo {
|
||||
return unwrapJSONCallResult(this.shim.getCompletionsAtPosition(fileName, position));
|
||||
}
|
||||
getCompletionEntryDetails(fileName: string, position: number, entryName: string): ts.CompletionEntryDetails {
|
||||
return unwrapJSONCallResult(this.shim.getCompletionEntryDetails(fileName, position, entryName));
|
||||
}
|
||||
getQuickInfoAtPosition(fileName: string, position: number): ts.QuickInfo {
|
||||
return unwrapJSONCallResult(this.shim.getQuickInfoAtPosition(fileName, position));
|
||||
}
|
||||
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): ts.TextSpan {
|
||||
return unwrapJSONCallResult(this.shim.getNameOrDottedNameSpan(fileName, startPos, endPos));
|
||||
}
|
||||
getBreakpointStatementAtPosition(fileName: string, position: number): ts.TextSpan {
|
||||
return unwrapJSONCallResult(this.shim.getBreakpointStatementAtPosition(fileName, position));
|
||||
}
|
||||
getSignatureHelpItems(fileName: string, position: number): ts.SignatureHelpItems {
|
||||
return unwrapJSONCallResult(this.shim.getSignatureHelpItems(fileName, position));
|
||||
}
|
||||
getRenameInfo(fileName: string, position: number): ts.RenameInfo {
|
||||
return unwrapJSONCallResult(this.shim.getRenameInfo(fileName, position));
|
||||
}
|
||||
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ts.RenameLocation[] {
|
||||
return unwrapJSONCallResult(this.shim.findRenameLocations(fileName, position, findInStrings, findInComments));
|
||||
}
|
||||
getDefinitionAtPosition(fileName: string, position: number): ts.DefinitionInfo[] {
|
||||
return unwrapJSONCallResult(this.shim.getDefinitionAtPosition(fileName, position));
|
||||
}
|
||||
getReferencesAtPosition(fileName: string, position: number): ts.ReferenceEntry[] {
|
||||
return unwrapJSONCallResult(this.shim.getReferencesAtPosition(fileName, position));
|
||||
}
|
||||
getOccurrencesAtPosition(fileName: string, position: number): ts.ReferenceEntry[] {
|
||||
return unwrapJSONCallResult(this.shim.getOccurrencesAtPosition(fileName, position));
|
||||
}
|
||||
getNavigateToItems(searchValue: string): ts.NavigateToItem[] {
|
||||
return unwrapJSONCallResult(this.shim.getNavigateToItems(searchValue));
|
||||
}
|
||||
getNavigationBarItems(fileName: string): ts.NavigationBarItem[] {
|
||||
return unwrapJSONCallResult(this.shim.getNavigationBarItems(fileName));
|
||||
}
|
||||
getOutliningSpans(fileName: string): ts.OutliningSpan[] {
|
||||
return unwrapJSONCallResult(this.shim.getOutliningSpans(fileName));
|
||||
}
|
||||
getTodoComments(fileName: string, descriptors: ts.TodoCommentDescriptor[]): ts.TodoComment[] {
|
||||
return unwrapJSONCallResult(this.shim.getTodoComments(fileName, JSON.stringify(descriptors)));
|
||||
}
|
||||
getBraceMatchingAtPosition(fileName: string, position: number): ts.TextSpan[] {
|
||||
return unwrapJSONCallResult(this.shim.getBraceMatchingAtPosition(fileName, position));
|
||||
}
|
||||
getIndentationAtPosition(fileName: string, position: number, options: ts.EditorOptions): number {
|
||||
return unwrapJSONCallResult(this.shim.getIndentationAtPosition(fileName, position, JSON.stringify(options)));
|
||||
}
|
||||
getFormattingEditsForRange(fileName: string, start: number, end: number, options: ts.FormatCodeOptions): ts.TextChange[] {
|
||||
return unwrapJSONCallResult(this.shim.getFormattingEditsForRange(fileName, start, end, JSON.stringify(options)));
|
||||
}
|
||||
getFormattingEditsForDocument(fileName: string, options: ts.FormatCodeOptions): ts.TextChange[] {
|
||||
return unwrapJSONCallResult(this.shim.getFormattingEditsForDocument(fileName, JSON.stringify(options)));
|
||||
}
|
||||
getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: ts.FormatCodeOptions): ts.TextChange[] {
|
||||
return unwrapJSONCallResult(this.shim.getFormattingEditsAfterKeystroke(fileName, position, key, JSON.stringify(options)));
|
||||
}
|
||||
getEmitOutput(fileName: string): ts.EmitOutput {
|
||||
return unwrapJSONCallResult(this.shim.getEmitOutput(fileName));
|
||||
}
|
||||
getProgram(): ts.Program {
|
||||
throw new Error("Program can not be marshaled across the shim layer.");
|
||||
}
|
||||
getSourceFile(fileName: string): ts.SourceFile {
|
||||
throw new Error("SourceFile can not be marshaled across the shim layer.");
|
||||
}
|
||||
dispose(): void { this.shim.dispose({}); }
|
||||
}
|
||||
|
||||
export class ShimLanugageServiceAdapter implements LanguageServiceAdapter {
|
||||
private host: ShimLanguageServiceHost;
|
||||
private factory: ts.TypeScriptServicesFactory;
|
||||
constructor(cancellationToken?: ts.CancellationToken, options?: ts.CompilerOptions) {
|
||||
this.host = new ShimLanguageServiceHost(cancellationToken, options);
|
||||
this.factory = new TypeScript.Services.TypeScriptServicesFactory();
|
||||
}
|
||||
getHost() { return this.host; }
|
||||
getLanguageService(): ts.LanguageService { return new LanguageServiceShimProxy(this.factory.createLanguageServiceShim(this.host)); }
|
||||
getClassifier(): ts.Classifier { return new ClassifierShimProxy(this.factory.createClassifierShim(this.host)); }
|
||||
getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo {
|
||||
var shimResult: {
|
||||
referencedFiles: ts.IFileReference[];
|
||||
importedFiles: ts.IFileReference[];
|
||||
isLibFile: boolean;
|
||||
};
|
||||
|
||||
var coreServicesShim = this.factory.createCoreServicesShim(this.host);
|
||||
shimResult = unwrapJSONCallResult(coreServicesShim.getPreProcessedFileInfo(fileName, ts.ScriptSnapshot.fromString(fileContents)));
|
||||
|
||||
var convertResult: ts.PreProcessedFileInfo = {
|
||||
referencedFiles: [],
|
||||
importedFiles: [],
|
||||
isLibFile: shimResult.isLibFile
|
||||
};
|
||||
|
||||
ts.forEach(shimResult.referencedFiles, refFile => {
|
||||
convertResult.referencedFiles.push({
|
||||
fileName: refFile.path,
|
||||
pos: refFile.position,
|
||||
end: refFile.position + refFile.length
|
||||
});
|
||||
});
|
||||
|
||||
var current = 0;
|
||||
var next = 1;
|
||||
while (current < temp.length) {
|
||||
var currentEdit = temp[current].edit;
|
||||
ts.forEach(shimResult.importedFiles, importedFile => {
|
||||
convertResult.importedFiles.push({
|
||||
fileName: importedFile.path,
|
||||
pos: importedFile.position,
|
||||
end: importedFile.position + importedFile.length
|
||||
});
|
||||
});
|
||||
|
||||
// Last edit
|
||||
if (next >= temp.length) {
|
||||
result.push(currentEdit);
|
||||
current++;
|
||||
continue;
|
||||
}
|
||||
var nextEdit = temp[next].edit;
|
||||
|
||||
var gap = nextEdit.span.start - ts.textSpanEnd(currentEdit.span);
|
||||
|
||||
// non-overlapping edits
|
||||
if (gap >= 0) {
|
||||
result.push(currentEdit);
|
||||
current = next;
|
||||
next++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// overlapping edits: for now, we only support ignoring an next edit
|
||||
// entirely contained in the current edit.
|
||||
if (ts.textSpanEnd(currentEdit.span) >= ts.textSpanEnd(nextEdit.span)) {
|
||||
next++;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
throw new Error("Trying to apply overlapping edits");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return convertResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,10 +61,13 @@ if (testConfigFile !== '') {
|
||||
runners.push(new ProjectRunner());
|
||||
break;
|
||||
case 'fourslash':
|
||||
runners.push(new FourslashRunner());
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.Native));
|
||||
break;
|
||||
case 'fourslash-shims':
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.Shims));
|
||||
break;
|
||||
case 'fourslash-generated':
|
||||
runners.push(new GeneratedFourslashRunner());
|
||||
runners.push(new GeneratedFourslashRunner(FourSlashTestType.Native));
|
||||
break;
|
||||
case 'rwc':
|
||||
runners.push(new RWCRunner());
|
||||
@@ -90,7 +93,8 @@ if (runners.length === 0) {
|
||||
}
|
||||
|
||||
// language services
|
||||
runners.push(new FourslashRunner());
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.Native));
|
||||
runners.push(new FourSlashRunner(FourSlashTestType.Shims));
|
||||
//runners.push(new GeneratedFourslashRunner());
|
||||
}
|
||||
|
||||
|
||||
@@ -1624,31 +1624,14 @@ module ts {
|
||||
|
||||
export var disableIncrementalParsing = false;
|
||||
|
||||
export function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange): SourceFile {
|
||||
if (textChangeRange && Debug.shouldAssert(AssertionLevel.Normal)) {
|
||||
var oldText = sourceFile.scriptSnapshot;
|
||||
var newText = scriptSnapshot;
|
||||
|
||||
Debug.assert((oldText.getLength() - textChangeRange.span.length + textChangeRange.newLength) === newText.getLength());
|
||||
|
||||
if (Debug.shouldAssert(AssertionLevel.VeryAggressive)) {
|
||||
var oldTextPrefix = oldText.getText(0, textChangeRange.span.start);
|
||||
var newTextPrefix = newText.getText(0, textChangeRange.span.start);
|
||||
Debug.assert(oldTextPrefix === newTextPrefix);
|
||||
|
||||
var oldTextSuffix = oldText.getText(textSpanEnd(textChangeRange.span), oldText.getLength());
|
||||
var newTextSuffix = newText.getText(textSpanEnd(textChangeRangeNewSpan(textChangeRange)), newText.getLength());
|
||||
Debug.assert(oldTextSuffix === newTextSuffix);
|
||||
}
|
||||
}
|
||||
|
||||
export function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile {
|
||||
// If we were given a text change range, and our version or open-ness changed, then
|
||||
// incrementally parse this file.
|
||||
if (textChangeRange) {
|
||||
if (version !== sourceFile.version) {
|
||||
// Once incremental parsing is ready, then just call into this function.
|
||||
if (!disableIncrementalParsing) {
|
||||
var newSourceFile = updateSourceFile(sourceFile, scriptSnapshot.getText(0, scriptSnapshot.getLength()), textChangeRange);
|
||||
var newSourceFile = updateSourceFile(sourceFile, scriptSnapshot.getText(0, scriptSnapshot.getLength()), textChangeRange, aggressiveChecks);
|
||||
setSourceFileFields(newSourceFile, scriptSnapshot, version);
|
||||
// after incremental parsing nameTable might not be up-to-date
|
||||
// drop it so it can be lazily recreated later
|
||||
@@ -2039,6 +2022,12 @@ module ts {
|
||||
return;
|
||||
}
|
||||
|
||||
// IMPORTANT - It is critical from this moment onward that we do not check
|
||||
// cancellation tokens. We are about to mutate source files from a previous program
|
||||
// instance. If we cancel midway through, we may end up in an inconsistent state where
|
||||
// the program points to old source files that have been invalidated because of
|
||||
// incremental parsing.
|
||||
|
||||
var oldSettings = program && program.getCompilerOptions();
|
||||
var newSettings = hostCache.compilationSettings();
|
||||
var changesInCompilationSettingsAffectSyntax = oldSettings && oldSettings.target !== newSettings.target;
|
||||
@@ -2073,8 +2062,6 @@ module ts {
|
||||
return;
|
||||
|
||||
function getOrCreateSourceFile(fileName: string): SourceFile {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
// The program is asking for this file, check first if the host can locate it.
|
||||
// If the host can not locate the file, then it does not exist. return undefined
|
||||
// to the program to allow reporting of errors for missing files.
|
||||
@@ -5380,9 +5367,6 @@ module ts {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
var fileContents = sourceFile.text;
|
||||
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
var result: TodoComment[] = [];
|
||||
|
||||
if (descriptors.length > 0) {
|
||||
|
||||
@@ -90,6 +90,7 @@ module ts {
|
||||
getCompilerOptionsDiagnostics(): string;
|
||||
|
||||
getSyntacticClassifications(fileName: string, start: number, length: number): string;
|
||||
getSemanticClassifications(fileName: string, start: number, length: number): string;
|
||||
|
||||
getCompletionsAtPosition(fileName: string, position: number): string;
|
||||
getCompletionEntryDetails(fileName: string, position: number, entryName: string): string;
|
||||
|
||||
@@ -1406,7 +1406,7 @@ declare module "typescript" {
|
||||
function createNode(kind: SyntaxKind): Node;
|
||||
function forEachChild<T>(node: Node, cbNode: (node: Node) => T, cbNodeArray?: (nodes: Node[]) => T): T;
|
||||
function modifierToFlag(token: SyntaxKind): NodeFlags;
|
||||
function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
|
||||
function isEvalOrArgumentsIdentifier(node: Node): boolean;
|
||||
function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes?: boolean): SourceFile;
|
||||
function isLeftHandSideExpression(expr: Expression): boolean;
|
||||
@@ -1897,7 +1897,7 @@ declare module "typescript" {
|
||||
}
|
||||
function createLanguageServiceSourceFile(fileName: string, scriptSnapshot: IScriptSnapshot, scriptTarget: ScriptTarget, version: string, setNodeParents: boolean): SourceFile;
|
||||
var disableIncrementalParsing: boolean;
|
||||
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
|
||||
function createDocumentRegistry(): DocumentRegistry;
|
||||
function preProcessFile(sourceText: string, readImportFiles?: boolean): PreProcessedFileInfo;
|
||||
function createLanguageService(host: LanguageServiceHost, documentRegistry?: DocumentRegistry): LanguageService;
|
||||
|
||||
@@ -4490,13 +4490,14 @@ declare module "typescript" {
|
||||
>SyntaxKind : SyntaxKind
|
||||
>NodeFlags : NodeFlags
|
||||
|
||||
function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
>updateSourceFile : (sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange) => SourceFile
|
||||
function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
|
||||
>updateSourceFile : (sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean) => SourceFile
|
||||
>sourceFile : SourceFile
|
||||
>SourceFile : SourceFile
|
||||
>newText : string
|
||||
>textChangeRange : TextChangeRange
|
||||
>TextChangeRange : TextChangeRange
|
||||
>aggressiveChecks : boolean
|
||||
>SourceFile : SourceFile
|
||||
|
||||
function isEvalOrArgumentsIdentifier(node: Node): boolean;
|
||||
@@ -5901,8 +5902,8 @@ declare module "typescript" {
|
||||
var disableIncrementalParsing: boolean;
|
||||
>disableIncrementalParsing : boolean
|
||||
|
||||
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
>updateLanguageServiceSourceFile : (sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange) => SourceFile
|
||||
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
|
||||
>updateLanguageServiceSourceFile : (sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean) => SourceFile
|
||||
>sourceFile : SourceFile
|
||||
>SourceFile : SourceFile
|
||||
>scriptSnapshot : IScriptSnapshot
|
||||
@@ -5910,6 +5911,7 @@ declare module "typescript" {
|
||||
>version : string
|
||||
>textChangeRange : TextChangeRange
|
||||
>TextChangeRange : TextChangeRange
|
||||
>aggressiveChecks : boolean
|
||||
>SourceFile : SourceFile
|
||||
|
||||
function createDocumentRegistry(): DocumentRegistry;
|
||||
|
||||
@@ -1437,7 +1437,7 @@ declare module "typescript" {
|
||||
function createNode(kind: SyntaxKind): Node;
|
||||
function forEachChild<T>(node: Node, cbNode: (node: Node) => T, cbNodeArray?: (nodes: Node[]) => T): T;
|
||||
function modifierToFlag(token: SyntaxKind): NodeFlags;
|
||||
function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
|
||||
function isEvalOrArgumentsIdentifier(node: Node): boolean;
|
||||
function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes?: boolean): SourceFile;
|
||||
function isLeftHandSideExpression(expr: Expression): boolean;
|
||||
@@ -1928,7 +1928,7 @@ declare module "typescript" {
|
||||
}
|
||||
function createLanguageServiceSourceFile(fileName: string, scriptSnapshot: IScriptSnapshot, scriptTarget: ScriptTarget, version: string, setNodeParents: boolean): SourceFile;
|
||||
var disableIncrementalParsing: boolean;
|
||||
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
|
||||
function createDocumentRegistry(): DocumentRegistry;
|
||||
function preProcessFile(sourceText: string, readImportFiles?: boolean): PreProcessedFileInfo;
|
||||
function createLanguageService(host: LanguageServiceHost, documentRegistry?: DocumentRegistry): LanguageService;
|
||||
|
||||
@@ -4634,13 +4634,14 @@ declare module "typescript" {
|
||||
>SyntaxKind : SyntaxKind
|
||||
>NodeFlags : NodeFlags
|
||||
|
||||
function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
>updateSourceFile : (sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange) => SourceFile
|
||||
function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
|
||||
>updateSourceFile : (sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean) => SourceFile
|
||||
>sourceFile : SourceFile
|
||||
>SourceFile : SourceFile
|
||||
>newText : string
|
||||
>textChangeRange : TextChangeRange
|
||||
>TextChangeRange : TextChangeRange
|
||||
>aggressiveChecks : boolean
|
||||
>SourceFile : SourceFile
|
||||
|
||||
function isEvalOrArgumentsIdentifier(node: Node): boolean;
|
||||
@@ -6045,8 +6046,8 @@ declare module "typescript" {
|
||||
var disableIncrementalParsing: boolean;
|
||||
>disableIncrementalParsing : boolean
|
||||
|
||||
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
>updateLanguageServiceSourceFile : (sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange) => SourceFile
|
||||
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
|
||||
>updateLanguageServiceSourceFile : (sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean) => SourceFile
|
||||
>sourceFile : SourceFile
|
||||
>SourceFile : SourceFile
|
||||
>scriptSnapshot : IScriptSnapshot
|
||||
@@ -6054,6 +6055,7 @@ declare module "typescript" {
|
||||
>version : string
|
||||
>textChangeRange : TextChangeRange
|
||||
>TextChangeRange : TextChangeRange
|
||||
>aggressiveChecks : boolean
|
||||
>SourceFile : SourceFile
|
||||
|
||||
function createDocumentRegistry(): DocumentRegistry;
|
||||
|
||||
@@ -1438,7 +1438,7 @@ declare module "typescript" {
|
||||
function createNode(kind: SyntaxKind): Node;
|
||||
function forEachChild<T>(node: Node, cbNode: (node: Node) => T, cbNodeArray?: (nodes: Node[]) => T): T;
|
||||
function modifierToFlag(token: SyntaxKind): NodeFlags;
|
||||
function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
|
||||
function isEvalOrArgumentsIdentifier(node: Node): boolean;
|
||||
function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes?: boolean): SourceFile;
|
||||
function isLeftHandSideExpression(expr: Expression): boolean;
|
||||
@@ -1929,7 +1929,7 @@ declare module "typescript" {
|
||||
}
|
||||
function createLanguageServiceSourceFile(fileName: string, scriptSnapshot: IScriptSnapshot, scriptTarget: ScriptTarget, version: string, setNodeParents: boolean): SourceFile;
|
||||
var disableIncrementalParsing: boolean;
|
||||
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
|
||||
function createDocumentRegistry(): DocumentRegistry;
|
||||
function preProcessFile(sourceText: string, readImportFiles?: boolean): PreProcessedFileInfo;
|
||||
function createLanguageService(host: LanguageServiceHost, documentRegistry?: DocumentRegistry): LanguageService;
|
||||
|
||||
@@ -4586,13 +4586,14 @@ declare module "typescript" {
|
||||
>SyntaxKind : SyntaxKind
|
||||
>NodeFlags : NodeFlags
|
||||
|
||||
function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
>updateSourceFile : (sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange) => SourceFile
|
||||
function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
|
||||
>updateSourceFile : (sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean) => SourceFile
|
||||
>sourceFile : SourceFile
|
||||
>SourceFile : SourceFile
|
||||
>newText : string
|
||||
>textChangeRange : TextChangeRange
|
||||
>TextChangeRange : TextChangeRange
|
||||
>aggressiveChecks : boolean
|
||||
>SourceFile : SourceFile
|
||||
|
||||
function isEvalOrArgumentsIdentifier(node: Node): boolean;
|
||||
@@ -5997,8 +5998,8 @@ declare module "typescript" {
|
||||
var disableIncrementalParsing: boolean;
|
||||
>disableIncrementalParsing : boolean
|
||||
|
||||
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
>updateLanguageServiceSourceFile : (sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange) => SourceFile
|
||||
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
|
||||
>updateLanguageServiceSourceFile : (sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean) => SourceFile
|
||||
>sourceFile : SourceFile
|
||||
>SourceFile : SourceFile
|
||||
>scriptSnapshot : IScriptSnapshot
|
||||
@@ -6006,6 +6007,7 @@ declare module "typescript" {
|
||||
>version : string
|
||||
>textChangeRange : TextChangeRange
|
||||
>TextChangeRange : TextChangeRange
|
||||
>aggressiveChecks : boolean
|
||||
>SourceFile : SourceFile
|
||||
|
||||
function createDocumentRegistry(): DocumentRegistry;
|
||||
|
||||
@@ -1475,7 +1475,7 @@ declare module "typescript" {
|
||||
function createNode(kind: SyntaxKind): Node;
|
||||
function forEachChild<T>(node: Node, cbNode: (node: Node) => T, cbNodeArray?: (nodes: Node[]) => T): T;
|
||||
function modifierToFlag(token: SyntaxKind): NodeFlags;
|
||||
function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
|
||||
function isEvalOrArgumentsIdentifier(node: Node): boolean;
|
||||
function createSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, setParentNodes?: boolean): SourceFile;
|
||||
function isLeftHandSideExpression(expr: Expression): boolean;
|
||||
@@ -1966,7 +1966,7 @@ declare module "typescript" {
|
||||
}
|
||||
function createLanguageServiceSourceFile(fileName: string, scriptSnapshot: IScriptSnapshot, scriptTarget: ScriptTarget, version: string, setNodeParents: boolean): SourceFile;
|
||||
var disableIncrementalParsing: boolean;
|
||||
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
|
||||
function createDocumentRegistry(): DocumentRegistry;
|
||||
function preProcessFile(sourceText: string, readImportFiles?: boolean): PreProcessedFileInfo;
|
||||
function createLanguageService(host: LanguageServiceHost, documentRegistry?: DocumentRegistry): LanguageService;
|
||||
|
||||
@@ -4759,13 +4759,14 @@ declare module "typescript" {
|
||||
>SyntaxKind : SyntaxKind
|
||||
>NodeFlags : NodeFlags
|
||||
|
||||
function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
>updateSourceFile : (sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange) => SourceFile
|
||||
function updateSourceFile(sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
|
||||
>updateSourceFile : (sourceFile: SourceFile, newText: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean) => SourceFile
|
||||
>sourceFile : SourceFile
|
||||
>SourceFile : SourceFile
|
||||
>newText : string
|
||||
>textChangeRange : TextChangeRange
|
||||
>TextChangeRange : TextChangeRange
|
||||
>aggressiveChecks : boolean
|
||||
>SourceFile : SourceFile
|
||||
|
||||
function isEvalOrArgumentsIdentifier(node: Node): boolean;
|
||||
@@ -6170,8 +6171,8 @@ declare module "typescript" {
|
||||
var disableIncrementalParsing: boolean;
|
||||
>disableIncrementalParsing : boolean
|
||||
|
||||
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange): SourceFile;
|
||||
>updateLanguageServiceSourceFile : (sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange) => SourceFile
|
||||
function updateLanguageServiceSourceFile(sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean): SourceFile;
|
||||
>updateLanguageServiceSourceFile : (sourceFile: SourceFile, scriptSnapshot: IScriptSnapshot, version: string, textChangeRange: TextChangeRange, aggressiveChecks?: boolean) => SourceFile
|
||||
>sourceFile : SourceFile
|
||||
>SourceFile : SourceFile
|
||||
>scriptSnapshot : IScriptSnapshot
|
||||
@@ -6179,6 +6180,7 @@ declare module "typescript" {
|
||||
>version : string
|
||||
>textChangeRange : TextChangeRange
|
||||
>TextChangeRange : TextChangeRange
|
||||
>aggressiveChecks : boolean
|
||||
>SourceFile : SourceFile
|
||||
|
||||
function createDocumentRegistry(): DocumentRegistry;
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
tests/cases/conformance/expressions/functionCalls/callWithSpread.ts(52,21): error TS2472: Spread operator in 'new' expressions is only available when targeting ECMAScript 6 and higher.
|
||||
|
||||
|
||||
==== tests/cases/conformance/expressions/functionCalls/callWithSpread.ts (1 errors) ====
|
||||
interface X {
|
||||
foo(x: number, y: number, ...z: string[]);
|
||||
}
|
||||
|
||||
function foo(x: number, y: number, ...z: string[]) {
|
||||
}
|
||||
|
||||
var a: string[];
|
||||
var z: number[];
|
||||
var obj: X;
|
||||
var xa: X[];
|
||||
|
||||
foo(1, 2, "abc");
|
||||
foo(1, 2, ...a);
|
||||
foo(1, 2, ...a, "abc");
|
||||
|
||||
obj.foo(1, 2, "abc");
|
||||
obj.foo(1, 2, ...a);
|
||||
obj.foo(1, 2, ...a, "abc");
|
||||
|
||||
(obj.foo)(1, 2, "abc");
|
||||
(obj.foo)(1, 2, ...a);
|
||||
(obj.foo)(1, 2, ...a, "abc");
|
||||
|
||||
xa[1].foo(1, 2, "abc");
|
||||
xa[1].foo(1, 2, ...a);
|
||||
xa[1].foo(1, 2, ...a, "abc");
|
||||
|
||||
(<Function>xa[1].foo)(...[1, 2, "abc"]);
|
||||
|
||||
class C {
|
||||
constructor(x: number, y: number, ...z: string[]) {
|
||||
this.foo(x, y);
|
||||
this.foo(x, y, ...z);
|
||||
}
|
||||
foo(x: number, y: number, ...z: string[]) {
|
||||
}
|
||||
}
|
||||
|
||||
class D extends C {
|
||||
constructor() {
|
||||
super(1, 2);
|
||||
super(1, 2, ...a);
|
||||
}
|
||||
foo() {
|
||||
super.foo(1, 2);
|
||||
super.foo(1, 2, ...a);
|
||||
}
|
||||
}
|
||||
|
||||
// Only supported in when target is ES6
|
||||
var c = new C(1, 2, ...a);
|
||||
~~~~
|
||||
!!! error TS2472: Spread operator in 'new' expressions is only available when targeting ECMAScript 6 and higher.
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
//// [callWithSpread.ts]
|
||||
interface X {
|
||||
foo(x: number, y: number, ...z: string[]);
|
||||
}
|
||||
|
||||
function foo(x: number, y: number, ...z: string[]) {
|
||||
}
|
||||
|
||||
var a: string[];
|
||||
var z: number[];
|
||||
var obj: X;
|
||||
var xa: X[];
|
||||
|
||||
foo(1, 2, "abc");
|
||||
foo(1, 2, ...a);
|
||||
foo(1, 2, ...a, "abc");
|
||||
|
||||
obj.foo(1, 2, "abc");
|
||||
obj.foo(1, 2, ...a);
|
||||
obj.foo(1, 2, ...a, "abc");
|
||||
|
||||
(obj.foo)(1, 2, "abc");
|
||||
(obj.foo)(1, 2, ...a);
|
||||
(obj.foo)(1, 2, ...a, "abc");
|
||||
|
||||
xa[1].foo(1, 2, "abc");
|
||||
xa[1].foo(1, 2, ...a);
|
||||
xa[1].foo(1, 2, ...a, "abc");
|
||||
|
||||
(<Function>xa[1].foo)(...[1, 2, "abc"]);
|
||||
|
||||
class C {
|
||||
constructor(x: number, y: number, ...z: string[]) {
|
||||
this.foo(x, y);
|
||||
this.foo(x, y, ...z);
|
||||
}
|
||||
foo(x: number, y: number, ...z: string[]) {
|
||||
}
|
||||
}
|
||||
|
||||
class D extends C {
|
||||
constructor() {
|
||||
super(1, 2);
|
||||
super(1, 2, ...a);
|
||||
}
|
||||
foo() {
|
||||
super.foo(1, 2);
|
||||
super.foo(1, 2, ...a);
|
||||
}
|
||||
}
|
||||
|
||||
// Only supported in when target is ES6
|
||||
var c = new C(1, 2, ...a);
|
||||
|
||||
|
||||
//// [callWithSpread.js]
|
||||
var __extends = this.__extends || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
__.prototype = b.prototype;
|
||||
d.prototype = new __();
|
||||
};
|
||||
function foo(x, y) {
|
||||
var z = [];
|
||||
for (var _i = 2; _i < arguments.length; _i++) {
|
||||
z[_i - 2] = arguments[_i];
|
||||
}
|
||||
}
|
||||
var a;
|
||||
var z;
|
||||
var obj;
|
||||
var xa;
|
||||
foo(1, 2, "abc");
|
||||
foo.apply(void 0, [1, 2].concat(a));
|
||||
foo.apply(void 0, [1, 2].concat(a, ["abc"]));
|
||||
obj.foo(1, 2, "abc");
|
||||
obj.foo.apply(obj, [1, 2].concat(a));
|
||||
obj.foo.apply(obj, [1, 2].concat(a, ["abc"]));
|
||||
(obj.foo)(1, 2, "abc");
|
||||
obj.foo.apply(obj, [1, 2].concat(a));
|
||||
obj.foo.apply(obj, [1, 2].concat(a, ["abc"]));
|
||||
xa[1].foo(1, 2, "abc");
|
||||
(_a = xa[1]).foo.apply(_a, [1, 2].concat(a));
|
||||
(_b = xa[1]).foo.apply(_b, [1, 2].concat(a, ["abc"]));
|
||||
(_c = xa[1]).foo.apply(_c, [1, 2, "abc"]);
|
||||
var C = (function () {
|
||||
function C(x, y) {
|
||||
var z = [];
|
||||
for (var _i = 2; _i < arguments.length; _i++) {
|
||||
z[_i - 2] = arguments[_i];
|
||||
}
|
||||
this.foo(x, y);
|
||||
this.foo.apply(this, [x, y].concat(z));
|
||||
}
|
||||
C.prototype.foo = function (x, y) {
|
||||
var z = [];
|
||||
for (var _i = 2; _i < arguments.length; _i++) {
|
||||
z[_i - 2] = arguments[_i];
|
||||
}
|
||||
};
|
||||
return C;
|
||||
})();
|
||||
var D = (function (_super) {
|
||||
__extends(D, _super);
|
||||
function D() {
|
||||
_super.call(this, 1, 2);
|
||||
_super.apply(this, [1, 2].concat(a));
|
||||
}
|
||||
D.prototype.foo = function () {
|
||||
_super.prototype.foo.call(this, 1, 2);
|
||||
_super.prototype.foo.apply(this, [1, 2].concat(a));
|
||||
};
|
||||
return D;
|
||||
})(C);
|
||||
// Only supported in when target is ES6
|
||||
var c = new C(1, 2, ...a);
|
||||
var _a, _b, _c;
|
||||
@@ -0,0 +1,105 @@
|
||||
//// [callWithSpreadES6.ts]
|
||||
|
||||
interface X {
|
||||
foo(x: number, y: number, ...z: string[]);
|
||||
}
|
||||
|
||||
function foo(x: number, y: number, ...z: string[]) {
|
||||
}
|
||||
|
||||
var a: string[];
|
||||
var z: number[];
|
||||
var obj: X;
|
||||
var xa: X[];
|
||||
|
||||
foo(1, 2, "abc");
|
||||
foo(1, 2, ...a);
|
||||
foo(1, 2, ...a, "abc");
|
||||
|
||||
obj.foo(1, 2, "abc");
|
||||
obj.foo(1, 2, ...a);
|
||||
obj.foo(1, 2, ...a, "abc");
|
||||
|
||||
(obj.foo)(1, 2, "abc");
|
||||
(obj.foo)(1, 2, ...a);
|
||||
(obj.foo)(1, 2, ...a, "abc");
|
||||
|
||||
xa[1].foo(1, 2, "abc");
|
||||
xa[1].foo(1, 2, ...a);
|
||||
xa[1].foo(1, 2, ...a, "abc");
|
||||
|
||||
(<Function>xa[1].foo)(...[1, 2, "abc"]);
|
||||
|
||||
class C {
|
||||
constructor(x: number, y: number, ...z: string[]) {
|
||||
this.foo(x, y);
|
||||
this.foo(x, y, ...z);
|
||||
}
|
||||
foo(x: number, y: number, ...z: string[]) {
|
||||
}
|
||||
}
|
||||
|
||||
class D extends C {
|
||||
constructor() {
|
||||
super(1, 2);
|
||||
super(1, 2, ...a);
|
||||
}
|
||||
foo() {
|
||||
super.foo(1, 2);
|
||||
super.foo(1, 2, ...a);
|
||||
}
|
||||
}
|
||||
|
||||
// Only supported in when target is ES6
|
||||
var c = new C(1, 2, ...a);
|
||||
|
||||
|
||||
//// [callWithSpreadES6.js]
|
||||
var __extends = this.__extends || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
__.prototype = b.prototype;
|
||||
d.prototype = new __();
|
||||
};
|
||||
function foo(x, y, ...z) {
|
||||
}
|
||||
var a;
|
||||
var z;
|
||||
var obj;
|
||||
var xa;
|
||||
foo(1, 2, "abc");
|
||||
foo(1, 2, ...a);
|
||||
foo(1, 2, ...a, "abc");
|
||||
obj.foo(1, 2, "abc");
|
||||
obj.foo(1, 2, ...a);
|
||||
obj.foo(1, 2, ...a, "abc");
|
||||
(obj.foo)(1, 2, "abc");
|
||||
(obj.foo)(1, 2, ...a);
|
||||
(obj.foo)(1, 2, ...a, "abc");
|
||||
xa[1].foo(1, 2, "abc");
|
||||
xa[1].foo(1, 2, ...a);
|
||||
xa[1].foo(1, 2, ...a, "abc");
|
||||
xa[1].foo(...[1, 2, "abc"]);
|
||||
var C = (function () {
|
||||
function C(x, y, ...z) {
|
||||
this.foo(x, y);
|
||||
this.foo(x, y, ...z);
|
||||
}
|
||||
C.prototype.foo = function (x, y, ...z) {
|
||||
};
|
||||
return C;
|
||||
})();
|
||||
var D = (function (_super) {
|
||||
__extends(D, _super);
|
||||
function D() {
|
||||
_super.call(this, 1, 2);
|
||||
_super.call(this, 1, 2, ...a);
|
||||
}
|
||||
D.prototype.foo = function () {
|
||||
_super.prototype.foo.call(this, 1, 2);
|
||||
_super.prototype.foo.call(this, 1, 2, ...a);
|
||||
};
|
||||
return D;
|
||||
})(C);
|
||||
// Only supported in when target is ES6
|
||||
var c = new C(1, 2, ...a);
|
||||
@@ -0,0 +1,196 @@
|
||||
=== tests/cases/conformance/expressions/functionCalls/callWithSpreadES6.ts ===
|
||||
|
||||
interface X {
|
||||
>X : X
|
||||
|
||||
foo(x: number, y: number, ...z: string[]);
|
||||
>foo : (x: number, y: number, ...z: string[]) => any
|
||||
>x : number
|
||||
>y : number
|
||||
>z : string[]
|
||||
}
|
||||
|
||||
function foo(x: number, y: number, ...z: string[]) {
|
||||
>foo : (x: number, y: number, ...z: string[]) => void
|
||||
>x : number
|
||||
>y : number
|
||||
>z : string[]
|
||||
}
|
||||
|
||||
var a: string[];
|
||||
>a : string[]
|
||||
|
||||
var z: number[];
|
||||
>z : number[]
|
||||
|
||||
var obj: X;
|
||||
>obj : X
|
||||
>X : X
|
||||
|
||||
var xa: X[];
|
||||
>xa : X[]
|
||||
>X : X
|
||||
|
||||
foo(1, 2, "abc");
|
||||
>foo(1, 2, "abc") : void
|
||||
>foo : (x: number, y: number, ...z: string[]) => void
|
||||
|
||||
foo(1, 2, ...a);
|
||||
>foo(1, 2, ...a) : void
|
||||
>foo : (x: number, y: number, ...z: string[]) => void
|
||||
>a : string[]
|
||||
|
||||
foo(1, 2, ...a, "abc");
|
||||
>foo(1, 2, ...a, "abc") : void
|
||||
>foo : (x: number, y: number, ...z: string[]) => void
|
||||
>a : string[]
|
||||
|
||||
obj.foo(1, 2, "abc");
|
||||
>obj.foo(1, 2, "abc") : any
|
||||
>obj.foo : (x: number, y: number, ...z: string[]) => any
|
||||
>obj : X
|
||||
>foo : (x: number, y: number, ...z: string[]) => any
|
||||
|
||||
obj.foo(1, 2, ...a);
|
||||
>obj.foo(1, 2, ...a) : any
|
||||
>obj.foo : (x: number, y: number, ...z: string[]) => any
|
||||
>obj : X
|
||||
>foo : (x: number, y: number, ...z: string[]) => any
|
||||
>a : string[]
|
||||
|
||||
obj.foo(1, 2, ...a, "abc");
|
||||
>obj.foo(1, 2, ...a, "abc") : any
|
||||
>obj.foo : (x: number, y: number, ...z: string[]) => any
|
||||
>obj : X
|
||||
>foo : (x: number, y: number, ...z: string[]) => any
|
||||
>a : string[]
|
||||
|
||||
(obj.foo)(1, 2, "abc");
|
||||
>(obj.foo)(1, 2, "abc") : any
|
||||
>(obj.foo) : (x: number, y: number, ...z: string[]) => any
|
||||
>obj.foo : (x: number, y: number, ...z: string[]) => any
|
||||
>obj : X
|
||||
>foo : (x: number, y: number, ...z: string[]) => any
|
||||
|
||||
(obj.foo)(1, 2, ...a);
|
||||
>(obj.foo)(1, 2, ...a) : any
|
||||
>(obj.foo) : (x: number, y: number, ...z: string[]) => any
|
||||
>obj.foo : (x: number, y: number, ...z: string[]) => any
|
||||
>obj : X
|
||||
>foo : (x: number, y: number, ...z: string[]) => any
|
||||
>a : string[]
|
||||
|
||||
(obj.foo)(1, 2, ...a, "abc");
|
||||
>(obj.foo)(1, 2, ...a, "abc") : any
|
||||
>(obj.foo) : (x: number, y: number, ...z: string[]) => any
|
||||
>obj.foo : (x: number, y: number, ...z: string[]) => any
|
||||
>obj : X
|
||||
>foo : (x: number, y: number, ...z: string[]) => any
|
||||
>a : string[]
|
||||
|
||||
xa[1].foo(1, 2, "abc");
|
||||
>xa[1].foo(1, 2, "abc") : any
|
||||
>xa[1].foo : (x: number, y: number, ...z: string[]) => any
|
||||
>xa[1] : X
|
||||
>xa : X[]
|
||||
>foo : (x: number, y: number, ...z: string[]) => any
|
||||
|
||||
xa[1].foo(1, 2, ...a);
|
||||
>xa[1].foo(1, 2, ...a) : any
|
||||
>xa[1].foo : (x: number, y: number, ...z: string[]) => any
|
||||
>xa[1] : X
|
||||
>xa : X[]
|
||||
>foo : (x: number, y: number, ...z: string[]) => any
|
||||
>a : string[]
|
||||
|
||||
xa[1].foo(1, 2, ...a, "abc");
|
||||
>xa[1].foo(1, 2, ...a, "abc") : any
|
||||
>xa[1].foo : (x: number, y: number, ...z: string[]) => any
|
||||
>xa[1] : X
|
||||
>xa : X[]
|
||||
>foo : (x: number, y: number, ...z: string[]) => any
|
||||
>a : string[]
|
||||
|
||||
(<Function>xa[1].foo)(...[1, 2, "abc"]);
|
||||
>(<Function>xa[1].foo)(...[1, 2, "abc"]) : any
|
||||
>(<Function>xa[1].foo) : Function
|
||||
><Function>xa[1].foo : Function
|
||||
>Function : Function
|
||||
>xa[1].foo : (x: number, y: number, ...z: string[]) => any
|
||||
>xa[1] : X
|
||||
>xa : X[]
|
||||
>foo : (x: number, y: number, ...z: string[]) => any
|
||||
>[1, 2, "abc"] : (string | number)[]
|
||||
|
||||
class C {
|
||||
>C : C
|
||||
|
||||
constructor(x: number, y: number, ...z: string[]) {
|
||||
>x : number
|
||||
>y : number
|
||||
>z : string[]
|
||||
|
||||
this.foo(x, y);
|
||||
>this.foo(x, y) : void
|
||||
>this.foo : (x: number, y: number, ...z: string[]) => void
|
||||
>this : C
|
||||
>foo : (x: number, y: number, ...z: string[]) => void
|
||||
>x : number
|
||||
>y : number
|
||||
|
||||
this.foo(x, y, ...z);
|
||||
>this.foo(x, y, ...z) : void
|
||||
>this.foo : (x: number, y: number, ...z: string[]) => void
|
||||
>this : C
|
||||
>foo : (x: number, y: number, ...z: string[]) => void
|
||||
>x : number
|
||||
>y : number
|
||||
>z : string[]
|
||||
}
|
||||
foo(x: number, y: number, ...z: string[]) {
|
||||
>foo : (x: number, y: number, ...z: string[]) => void
|
||||
>x : number
|
||||
>y : number
|
||||
>z : string[]
|
||||
}
|
||||
}
|
||||
|
||||
class D extends C {
|
||||
>D : D
|
||||
>C : C
|
||||
|
||||
constructor() {
|
||||
super(1, 2);
|
||||
>super(1, 2) : void
|
||||
>super : typeof C
|
||||
|
||||
super(1, 2, ...a);
|
||||
>super(1, 2, ...a) : void
|
||||
>super : typeof C
|
||||
>a : string[]
|
||||
}
|
||||
foo() {
|
||||
>foo : () => void
|
||||
|
||||
super.foo(1, 2);
|
||||
>super.foo(1, 2) : void
|
||||
>super.foo : (x: number, y: number, ...z: string[]) => void
|
||||
>super : C
|
||||
>foo : (x: number, y: number, ...z: string[]) => void
|
||||
|
||||
super.foo(1, 2, ...a);
|
||||
>super.foo(1, 2, ...a) : void
|
||||
>super.foo : (x: number, y: number, ...z: string[]) => void
|
||||
>super : C
|
||||
>foo : (x: number, y: number, ...z: string[]) => void
|
||||
>a : string[]
|
||||
}
|
||||
}
|
||||
|
||||
// Only supported in when target is ES6
|
||||
var c = new C(1, 2, ...a);
|
||||
>c : C
|
||||
>new C(1, 2, ...a) : C
|
||||
>C : typeof C
|
||||
>a : string[]
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
|
||||
1 >while (true) {
|
||||
|
||||
~~~~~~~~~~~~~~~ => Pos: (0 to 14) SpanInfo: {"start":0,"length":12}
|
||||
>while (true)
|
||||
>:=> (line 1, col 0) to (line 1, col 12)
|
||||
--------------------------------
|
||||
2 > break;
|
||||
|
||||
~~~~~~~~~~~ => Pos: (15 to 25) SpanInfo: {"start":19,"length":5}
|
||||
>break
|
||||
>:=> (line 2, col 4) to (line 2, col 9)
|
||||
--------------------------------
|
||||
3 >}
|
||||
|
||||
~~ => Pos: (26 to 27) SpanInfo: {"start":19,"length":5}
|
||||
>break
|
||||
>:=> (line 2, col 4) to (line 2, col 9)
|
||||
--------------------------------
|
||||
4 >y: while (true) {
|
||||
|
||||
~~~~~~~~~~~~~~~~~~ => Pos: (28 to 45) SpanInfo: {"start":31,"length":12}
|
||||
>while (true)
|
||||
>:=> (line 4, col 3) to (line 4, col 15)
|
||||
--------------------------------
|
||||
5 > break y;
|
||||
|
||||
~~~~~~~~~~~~~ => Pos: (46 to 58) SpanInfo: {"start":50,"length":7}
|
||||
>break y
|
||||
>:=> (line 5, col 4) to (line 5, col 11)
|
||||
--------------------------------
|
||||
6 >}
|
||||
|
||||
~~ => Pos: (59 to 60) SpanInfo: {"start":50,"length":7}
|
||||
>break y
|
||||
>:=> (line 5, col 4) to (line 5, col 11)
|
||||
--------------------------------
|
||||
7 >while (true) {
|
||||
|
||||
~~~~~~~~~~~~~~~ => Pos: (61 to 75) SpanInfo: {"start":61,"length":12}
|
||||
>while (true)
|
||||
>:=> (line 7, col 0) to (line 7, col 12)
|
||||
--------------------------------
|
||||
8 > continue;
|
||||
|
||||
~~~~~~~~~~~~~~ => Pos: (76 to 89) SpanInfo: {"start":80,"length":8}
|
||||
>continue
|
||||
>:=> (line 8, col 4) to (line 8, col 12)
|
||||
--------------------------------
|
||||
9 >}
|
||||
|
||||
~~ => Pos: (90 to 91) SpanInfo: {"start":80,"length":8}
|
||||
>continue
|
||||
>:=> (line 8, col 4) to (line 8, col 12)
|
||||
--------------------------------
|
||||
10 >z: while (true) {
|
||||
|
||||
~~~~~~~~~~~~~~~~~~ => Pos: (92 to 109) SpanInfo: {"start":95,"length":12}
|
||||
>while (true)
|
||||
>:=> (line 10, col 3) to (line 10, col 15)
|
||||
--------------------------------
|
||||
11 > continue z;
|
||||
|
||||
~~~~~~~~~~~~~~~~ => Pos: (110 to 125) SpanInfo: {"start":114,"length":10}
|
||||
>continue z
|
||||
>:=> (line 11, col 4) to (line 11, col 14)
|
||||
--------------------------------
|
||||
12 >}
|
||||
~ => Pos: (126 to 126) SpanInfo: {"start":114,"length":10}
|
||||
>continue z
|
||||
>:=> (line 11, col 4) to (line 11, col 14)
|
||||
@@ -0,0 +1,30 @@
|
||||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/shims/inputFile1.js
|
||||
var x = 5;
|
||||
var Bar = (function () {
|
||||
function Bar() {
|
||||
}
|
||||
return Bar;
|
||||
})();
|
||||
FileName : tests/cases/fourslash/shims/inputFile1.d.ts
|
||||
declare var x: number;
|
||||
declare class Bar {
|
||||
x: string;
|
||||
y: number;
|
||||
}
|
||||
|
||||
EmitSkipped: false
|
||||
FileName : tests/cases/fourslash/shims/inputFile2.js
|
||||
var x1 = "hello world";
|
||||
var Foo = (function () {
|
||||
function Foo() {
|
||||
}
|
||||
return Foo;
|
||||
})();
|
||||
FileName : tests/cases/fourslash/shims/inputFile2.d.ts
|
||||
declare var x1: string;
|
||||
declare class Foo {
|
||||
x: string;
|
||||
y: number;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
tests/cases/compiler/letInLetOrConstDeclarations.ts(2,9): error TS4089: 'let' is not allowed to be used as a name in 'let' or 'const' declarations.
|
||||
tests/cases/compiler/letInLetOrConstDeclarations.ts(3,14): error TS4089: 'let' is not allowed to be used as a name in 'let' or 'const' declarations.
|
||||
tests/cases/compiler/letInLetOrConstDeclarations.ts(6,11): error TS4089: 'let' is not allowed to be used as a name in 'let' or 'const' declarations.
|
||||
|
||||
|
||||
==== tests/cases/compiler/letInLetOrConstDeclarations.ts (3 errors) ====
|
||||
{
|
||||
let let = 1; // should error
|
||||
~~~
|
||||
!!! error TS4089: 'let' is not allowed to be used as a name in 'let' or 'const' declarations.
|
||||
for (let let in []) { } // should error
|
||||
~~~
|
||||
!!! error TS4089: 'let' is not allowed to be used as a name in 'let' or 'const' declarations.
|
||||
}
|
||||
{
|
||||
const let = 1; // should error
|
||||
~~~
|
||||
!!! error TS4089: 'let' is not allowed to be used as a name in 'let' or 'const' declarations.
|
||||
}
|
||||
{
|
||||
function let() { // should be ok
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
//// [letInLetOrConstDeclarations.ts]
|
||||
{
|
||||
let let = 1; // should error
|
||||
for (let let in []) { } // should error
|
||||
}
|
||||
{
|
||||
const let = 1; // should error
|
||||
}
|
||||
{
|
||||
function let() { // should be ok
|
||||
}
|
||||
}
|
||||
|
||||
//// [letInLetOrConstDeclarations.js]
|
||||
{
|
||||
let let = 1; // should error
|
||||
for (let let in []) { } // should error
|
||||
}
|
||||
{
|
||||
const let = 1; // should error
|
||||
}
|
||||
{
|
||||
function let() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// @target: es6
|
||||
{
|
||||
let let = 1; // should error
|
||||
for (let let in []) { } // should error
|
||||
}
|
||||
{
|
||||
const let = 1; // should error
|
||||
}
|
||||
{
|
||||
function let() { // should be ok
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
interface X {
|
||||
foo(x: number, y: number, ...z: string[]);
|
||||
}
|
||||
|
||||
function foo(x: number, y: number, ...z: string[]) {
|
||||
}
|
||||
|
||||
var a: string[];
|
||||
var z: number[];
|
||||
var obj: X;
|
||||
var xa: X[];
|
||||
|
||||
foo(1, 2, "abc");
|
||||
foo(1, 2, ...a);
|
||||
foo(1, 2, ...a, "abc");
|
||||
|
||||
obj.foo(1, 2, "abc");
|
||||
obj.foo(1, 2, ...a);
|
||||
obj.foo(1, 2, ...a, "abc");
|
||||
|
||||
(obj.foo)(1, 2, "abc");
|
||||
(obj.foo)(1, 2, ...a);
|
||||
(obj.foo)(1, 2, ...a, "abc");
|
||||
|
||||
xa[1].foo(1, 2, "abc");
|
||||
xa[1].foo(1, 2, ...a);
|
||||
xa[1].foo(1, 2, ...a, "abc");
|
||||
|
||||
(<Function>xa[1].foo)(...[1, 2, "abc"]);
|
||||
|
||||
class C {
|
||||
constructor(x: number, y: number, ...z: string[]) {
|
||||
this.foo(x, y);
|
||||
this.foo(x, y, ...z);
|
||||
}
|
||||
foo(x: number, y: number, ...z: string[]) {
|
||||
}
|
||||
}
|
||||
|
||||
class D extends C {
|
||||
constructor() {
|
||||
super(1, 2);
|
||||
super(1, 2, ...a);
|
||||
}
|
||||
foo() {
|
||||
super.foo(1, 2);
|
||||
super.foo(1, 2, ...a);
|
||||
}
|
||||
}
|
||||
|
||||
// Only supported in when target is ES6
|
||||
var c = new C(1, 2, ...a);
|
||||
@@ -0,0 +1,54 @@
|
||||
// @target: ES6
|
||||
|
||||
interface X {
|
||||
foo(x: number, y: number, ...z: string[]);
|
||||
}
|
||||
|
||||
function foo(x: number, y: number, ...z: string[]) {
|
||||
}
|
||||
|
||||
var a: string[];
|
||||
var z: number[];
|
||||
var obj: X;
|
||||
var xa: X[];
|
||||
|
||||
foo(1, 2, "abc");
|
||||
foo(1, 2, ...a);
|
||||
foo(1, 2, ...a, "abc");
|
||||
|
||||
obj.foo(1, 2, "abc");
|
||||
obj.foo(1, 2, ...a);
|
||||
obj.foo(1, 2, ...a, "abc");
|
||||
|
||||
(obj.foo)(1, 2, "abc");
|
||||
(obj.foo)(1, 2, ...a);
|
||||
(obj.foo)(1, 2, ...a, "abc");
|
||||
|
||||
xa[1].foo(1, 2, "abc");
|
||||
xa[1].foo(1, 2, ...a);
|
||||
xa[1].foo(1, 2, ...a, "abc");
|
||||
|
||||
(<Function>xa[1].foo)(...[1, 2, "abc"]);
|
||||
|
||||
class C {
|
||||
constructor(x: number, y: number, ...z: string[]) {
|
||||
this.foo(x, y);
|
||||
this.foo(x, y, ...z);
|
||||
}
|
||||
foo(x: number, y: number, ...z: string[]) {
|
||||
}
|
||||
}
|
||||
|
||||
class D extends C {
|
||||
constructor() {
|
||||
super(1, 2);
|
||||
super(1, 2, ...a);
|
||||
}
|
||||
foo() {
|
||||
super.foo(1, 2);
|
||||
super.foo(1, 2, ...a);
|
||||
}
|
||||
}
|
||||
|
||||
// Only supported in when target is ES6
|
||||
var c = new C(1, 2, ...a);
|
||||
@@ -12,4 +12,3 @@ edit.disableFormatting();
|
||||
goTo.marker('1');
|
||||
|
||||
edit.insert(" compareTo(): number;\n");
|
||||
diagnostics.validateTypesAtPositions(168,84,53,118,22);
|
||||
|
||||
@@ -14,4 +14,3 @@ edit.disableFormatting();
|
||||
goTo.marker('1');
|
||||
|
||||
edit.insert(", 'world'");
|
||||
diagnostics.validateTypesAtPositions(78);
|
||||
|
||||
@@ -23,5 +23,4 @@ goTo.marker('2');
|
||||
edit.deleteAtCaret(7);
|
||||
|
||||
goTo.marker('4');
|
||||
diagnostics.validateTypesAtPositions(43);
|
||||
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
/// <reference path="../fourslash.ts" />
|
||||
|
||||
//// interface Iterator<T> {
|
||||
//// (value: T, index: any): U;
|
||||
//// }
|
||||
////
|
||||
//// interface WrappedArray<T> {
|
||||
//// map<U>(iterator: Iterator<T, U>): U[];
|
||||
//// }
|
||||
////
|
||||
//// interface Underscore {
|
||||
//// <T>(list: T[]): WrappedArray<T>;
|
||||
//// map<T, U>(list: T[], iterator: Iterator<T, U>, context?: any): U[];
|
||||
//// }
|
||||
////
|
||||
//// declare var _: Underscore;
|
||||
////
|
||||
//// var a: string[];
|
||||
//// var b = _.map(a, x => x.length); // Type any[], should be number[]
|
||||
//// var c = _(a).map();
|
||||
//// var d = a.map(x => x.length);
|
||||
//// var bb = _.map(aa, x => x.length);
|
||||
//// var cc = _(aa).map(x => x.length); // Error, could not select overload
|
||||
//// var dd = aa.map(x => x.length); // Error, could not select overload
|
||||
////
|
||||
////
|
||||
////
|
||||
////
|
||||
|
||||
edit.disableFormatting();
|
||||
diagnostics.validateTypesAtPositions(364);
|
||||
@@ -1,7 +0,0 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//// function foo2<T>(test);
|
||||
//// function foo2<T>() { }
|
||||
//// /**/foo2<>("");
|
||||
goTo.marker();
|
||||
diagnostics.validateTypeAtCurrentPosition();
|
||||
@@ -80,16 +80,6 @@ module FourSlashInterface {
|
||||
}
|
||||
}
|
||||
|
||||
export class diagnostics {
|
||||
public validateTypeAtCurrentPosition() {
|
||||
return this.validateTypesAtPositions(FourSlash.currentTestState.currentCaretPosition);
|
||||
}
|
||||
|
||||
public validateTypesAtPositions(...positions: number[]) {
|
||||
return FourSlash.currentTestState.verifyTypesAgainstFullCheckAtPositions(positions);
|
||||
}
|
||||
}
|
||||
|
||||
export class goTo {
|
||||
// Moves the caret to the specified marker,
|
||||
// or the anonymous marker ('/**/') if no name
|
||||
@@ -565,11 +555,11 @@ module FourSlashInterface {
|
||||
|
||||
export class cancellation {
|
||||
public resetCancelled() {
|
||||
FourSlash.currentTestState.cancellationToken.resetCancelled();
|
||||
FourSlash.currentTestState.resetCancelled();
|
||||
}
|
||||
|
||||
public setCancelled(numberOfCalls: number = 0) {
|
||||
FourSlash.currentTestState.cancellationToken.setCancelled(numberOfCalls);
|
||||
FourSlash.currentTestState.setCancelled(numberOfCalls);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -651,7 +641,6 @@ module fs {
|
||||
export var edit = new FourSlashInterface.edit();
|
||||
export var debug = new FourSlashInterface.debug();
|
||||
export var format = new FourSlashInterface.format();
|
||||
export var diagnostics = new FourSlashInterface.diagnostics();
|
||||
export var cancellation = new FourSlashInterface.cancellation();
|
||||
}
|
||||
module ts {
|
||||
@@ -670,6 +659,5 @@ var verify = new FourSlashInterface.verify();
|
||||
var edit = new FourSlashInterface.edit();
|
||||
var debug = new FourSlashInterface.debug();
|
||||
var format = new FourSlashInterface.format();
|
||||
var diagnostics = new FourSlashInterface.diagnostics();
|
||||
var cancellation = new FourSlashInterface.cancellation();
|
||||
var classification = FourSlashInterface.classification;
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////declare module A.B {
|
||||
//// export class C { }
|
||||
////}
|
||||
////
|
||||
////import ab = A.B;
|
||||
////
|
||||
////class D extends ab.C/**/{ }
|
||||
|
||||
goTo.marker();
|
||||
diagnostics.validateTypesAtPositions(FourSlash.currentTestState.currentCaretPosition);
|
||||
@@ -179,5 +179,5 @@
|
||||
////{| "indent": 0 |}
|
||||
|
||||
test.markers().forEach((marker) => {
|
||||
verify.indentationAtPositionIs('tests/cases/fourslash/indentation.ts', marker.position, marker.data.indent);
|
||||
verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indent);
|
||||
});
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//// var x: Number;
|
||||
//// var y: Number;
|
||||
//// var z = x ;
|
||||
|
||||
edit.disableFormatting();
|
||||
diagnostics.validateTypesAtPositions(28);
|
||||
@@ -1,29 +0,0 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//// class A<T, U extends T> { }
|
||||
//// class B<T extends Object, U extends T> {
|
||||
//// data: A<Object, Object>;
|
||||
//// }
|
||||
////
|
||||
//// // Below 2 should compile without error
|
||||
//// var x: A< { }, { b: number }>;
|
||||
//// var y: B< { a: string }, { }>;
|
||||
////
|
||||
////
|
||||
//// // Below should be in error
|
||||
//// var x1: A<{ a: string;}>;
|
||||
//// var x2: A<{ a: number }>;
|
||||
//// var x3: B<{ a: string;}, { b: string }>;
|
||||
//// var x4: B<{ a: string;}>;
|
||||
//// var x5: A<{ a: string; b: number }, { a: string }>;
|
||||
//// var x6: B<>;
|
||||
////
|
||||
//// interface I1 {
|
||||
//// a: string;
|
||||
//// }
|
||||
//// var x8: B<I2, I1>;
|
||||
////
|
||||
|
||||
edit.disableFormatting();
|
||||
diagnostics.validateTypesAtPositions(34);
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//// function f18(a?:string, ...b){}
|
||||
////
|
||||
//// function f19(a?:string, b?){}
|
||||
////
|
||||
//// function f20(a:string, b?:string, ...c:number[]){}
|
||||
////
|
||||
//// function f21(a:string, b?:string, ...d:number[]){}
|
||||
|
||||
edit.disableFormatting();
|
||||
diagnostics.validateTypesAtPositions(133);
|
||||
@@ -0,0 +1,38 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//@Filename: findAllRefsOnDefinition-import.ts
|
||||
////export class Test{
|
||||
////
|
||||
//// constructor(){
|
||||
////
|
||||
//// }
|
||||
////
|
||||
//// public /*1*/start(){
|
||||
//// return this;
|
||||
//// }
|
||||
////
|
||||
//// public stop(){
|
||||
//// return this;
|
||||
//// }
|
||||
////}
|
||||
|
||||
//@Filename: findAllRefsOnDefinition.ts
|
||||
////import Second = require("findAllRefsOnDefinition-import");
|
||||
////
|
||||
////var second = new Second.Test()
|
||||
////second.start();
|
||||
////second.stop();
|
||||
|
||||
goTo.file("findAllRefsOnDefinition-import.ts");
|
||||
goTo.marker("1");
|
||||
|
||||
verify.referencesCountIs(2);
|
||||
|
||||
cancellation.setCancelled();
|
||||
goTo.marker("1");
|
||||
verifyOperationIsCancelled(() => verify.referencesCountIs(0) );
|
||||
|
||||
// verify that internal state is still correct
|
||||
cancellation.resetCancelled();
|
||||
goTo.marker("1");
|
||||
verify.referencesCountIs(2);
|
||||
@@ -0,0 +1,43 @@
|
||||
/// <reference path="fourslash.ts"/>
|
||||
|
||||
//////curly braces
|
||||
////module Foo [|{
|
||||
//// class Bar [|{
|
||||
//// private f() [|{
|
||||
//// }|]
|
||||
////
|
||||
//// private f2() [|{
|
||||
//// if (true) [|{ }|] [|{ }|];
|
||||
//// }|]
|
||||
//// }|]
|
||||
////}|]
|
||||
////
|
||||
//////parenthesis
|
||||
////class FooBar {
|
||||
//// private f[|()|] {
|
||||
//// return [|([|(1 + 1)|])|];
|
||||
//// }
|
||||
////
|
||||
//// private f2[|()|] {
|
||||
//// if [|(true)|] { }
|
||||
//// }
|
||||
////}
|
||||
////
|
||||
//////square brackets
|
||||
////class Baz {
|
||||
//// private f() {
|
||||
//// var a: any[|[]|] = [|[[|[1, 2]|], [|[3, 4]|], 5]|];
|
||||
//// }
|
||||
////}
|
||||
////
|
||||
////// angular brackets
|
||||
////class TemplateTest [|<T1, T2 extends Array>|] {
|
||||
//// public foo(a, b) {
|
||||
//// return [|<any>|] a;
|
||||
//// }
|
||||
////}
|
||||
|
||||
test.ranges().forEach((range) => {
|
||||
verify.matchingBracePositionInCurrentFile(range.start, range.end - 1);
|
||||
verify.matchingBracePositionInCurrentFile(range.end - 1, range.start);
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @BaselineFile: getBreakpointStatementAtPosition.baseline
|
||||
// @Filename: getBreakpointStatementAtPosition.ts
|
||||
////while (true) {
|
||||
//// break;
|
||||
////}
|
||||
////y: while (true) {
|
||||
//// break y;
|
||||
////}
|
||||
////while (true) {
|
||||
//// continue;
|
||||
////}
|
||||
////z: while (true) {
|
||||
//// continue z;
|
||||
////}
|
||||
verify.baselineCurrentFileBreakpointLocations();
|
||||
@@ -0,0 +1,20 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
////function foo(strOrNum: string | number) {
|
||||
//// /*1*/
|
||||
//// if (typeof strOrNum === "number") {
|
||||
//// /*2*/
|
||||
//// }
|
||||
//// else {
|
||||
//// /*3*/
|
||||
//// }
|
||||
////}
|
||||
|
||||
goTo.marker('1');
|
||||
verify.completionListContains("strOrNum", "(parameter) strOrNum: string | number");
|
||||
|
||||
goTo.marker('2');
|
||||
verify.completionListContains("strOrNum", "(parameter) strOrNum: number");
|
||||
|
||||
goTo.marker('3');
|
||||
verify.completionListContains("strOrNum", "(parameter) strOrNum: string");
|
||||
@@ -0,0 +1,29 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: goToDefinitionDifferentFile_Definition.ts
|
||||
////var /*remoteVariableDefinition*/remoteVariable;
|
||||
/////*remoteFunctionDefinition*/function remoteFunction() { }
|
||||
/////*remoteClassDefinition*/class remoteClass { }
|
||||
/////*remoteInterfaceDefinition*/interface remoteInterface{ }
|
||||
/////*remoteModuleDefinition*/module remoteModule{ export var foo = 1;}
|
||||
|
||||
// @Filename: goToDefinitionDifferentFile_Consumption.ts
|
||||
/////*remoteVariableReference*/remoteVariable = 1;
|
||||
/////*remoteFunctionReference*/remoteFunction();
|
||||
////var foo = new /*remoteClassReference*/remoteClass();
|
||||
////class fooCls implements /*remoteInterfaceReference*/remoteInterface { }
|
||||
////var fooVar = /*remoteModuleReference*/remoteModule.foo;
|
||||
|
||||
var markerList = [
|
||||
"remoteVariable",
|
||||
"remoteFunction",
|
||||
"remoteClass",
|
||||
"remoteInterface",
|
||||
"remoteModule",
|
||||
];
|
||||
|
||||
markerList.forEach((marker) => {
|
||||
goTo.marker(marker + 'Reference');
|
||||
goTo.definition();
|
||||
verify.caretAtMarker(marker + 'Definition');
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @BaselineFile: getEmitOutput.baseline
|
||||
// @declaration: true
|
||||
|
||||
// @Filename: inputFile1.ts
|
||||
// @emitThisFile: true
|
||||
//// var x: number = 5;
|
||||
//// class Bar {
|
||||
//// x : string;
|
||||
//// y : number
|
||||
//// }
|
||||
|
||||
// @Filename: inputFile2.ts
|
||||
// @emitThisFile: true
|
||||
//// var x1: string = "hello world";
|
||||
//// class Foo{
|
||||
//// x : string;
|
||||
//// y : number;
|
||||
//// }
|
||||
|
||||
verify.baselineGetEmitOutput();
|
||||
@@ -0,0 +1,21 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
////class Bar {
|
||||
//// {| "indentation": 4|}
|
||||
//// private foo: string = "";
|
||||
//// {| "indentation": 4|}
|
||||
//// private f() {
|
||||
//// var a: any[] = [[1, 2], [3, 4], 5];
|
||||
//// {| "indentation": 8|}
|
||||
//// return ((1 + 1));
|
||||
//// }
|
||||
//// {| "indentation": 4|}
|
||||
//// private f2() {
|
||||
//// if (true) { } { };
|
||||
//// }
|
||||
////}
|
||||
////{| "indentation": 0|}
|
||||
|
||||
test.markers().forEach((marker) => {
|
||||
verify.indentationAtPositionIs(marker.fileName, marker.position, marker.data.indentation);
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
/// <reference path="fourslash.ts"/>
|
||||
|
||||
/////// Module
|
||||
////{| "itemName": "Shapes", "kind": "module", "parentName": "" |}module Shapes {
|
||||
////
|
||||
//// // Class
|
||||
//// {| "itemName": "Point", "kind": "class", "parentName": "Shapes" |}export class Point {
|
||||
//// // Instance member
|
||||
//// {| "itemName": "origin", "kind": "property", "parentName": "Point", "matchKind": "exact"|}private origin = 0.0;
|
||||
////
|
||||
//// {| "itemName": "distFromZero", "kind": "property", "parentName": "Point", "matchKind": "exact"|}private distFromZero = 0.0;
|
||||
////
|
||||
//// // Getter
|
||||
//// {| "itemName": "distance", "kind": "getter", "parentName": "Point", "matchKind": "exact" |}get distance(): number { return 0; }
|
||||
//// }
|
||||
////}
|
||||
////
|
||||
////// Local variables
|
||||
////{| "itemName": "point", "kind": "var", "parentName": "", "matchKind": "exact"|}var point = new Shapes.Point();
|
||||
|
||||
//// Testing for exact matching of navigationItems
|
||||
|
||||
test.markers().forEach((marker) => {
|
||||
if (marker.data) {
|
||||
verify.navigationItemsListContains(marker.data.itemName, marker.data.kind, marker.data.itemName, marker.data.matchKind, marker.fileName, marker.data.parentName);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//// {| "itemName": "c", "kind": "const", "parentName": "" |}const c = 0;
|
||||
|
||||
test.markers().forEach(marker => {
|
||||
verify.getScriptLexicalStructureListContains(
|
||||
marker.data.itemName,
|
||||
marker.data.kind,
|
||||
marker.fileName,
|
||||
marker.data.parentName,
|
||||
marker.data.isAdditionalRange,
|
||||
marker.position);
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
/////*0*/
|
||||
////interface A {
|
||||
//// foo: string;
|
||||
////}
|
||||
////function foo(x: A) {
|
||||
//// x.f/*1*/oo
|
||||
////}
|
||||
|
||||
goTo.marker("1");
|
||||
verify.occurrencesAtPositionCount(2);
|
||||
|
||||
goTo.marker("0");
|
||||
edit.insert("\r\n");
|
||||
|
||||
goTo.marker("1");
|
||||
verify.occurrencesAtPositionCount(2);
|
||||
@@ -0,0 +1,113 @@
|
||||
/// <reference path="fourslash.ts"/>
|
||||
|
||||
////// interface
|
||||
////interface IFoo[| {
|
||||
//// getDist(): number;
|
||||
////}|]
|
||||
////
|
||||
////// class members
|
||||
////class Foo[| {
|
||||
//// constructor()[| {
|
||||
//// }|]
|
||||
////
|
||||
//// public foo(): number[| {
|
||||
//// return 0;
|
||||
//// }|]
|
||||
////
|
||||
//// public get X()[| {
|
||||
//// return 1;
|
||||
//// }|]
|
||||
////
|
||||
//// public set X(v: number)[| {
|
||||
//// }|]
|
||||
////
|
||||
//// public member = function f()[| {
|
||||
////
|
||||
//// }|]
|
||||
////}|]
|
||||
////switch(1)[| {
|
||||
//// case 1: break;
|
||||
////}|]
|
||||
////
|
||||
////var array =[| [
|
||||
//// 1,
|
||||
//// 2
|
||||
////]|]
|
||||
////
|
||||
////// modules
|
||||
////module m1[| {
|
||||
//// module m2[| { }|]
|
||||
//// module m3[| {
|
||||
//// function foo()[| {
|
||||
////
|
||||
//// }|]
|
||||
////
|
||||
//// interface IFoo2[| {
|
||||
////
|
||||
//// }|]
|
||||
////
|
||||
//// class foo2 implements IFoo2[| {
|
||||
////
|
||||
//// }|]
|
||||
//// }|]
|
||||
////}|]
|
||||
////
|
||||
////// function declaration
|
||||
////function foo(): number[| {
|
||||
//// return 0;
|
||||
////}|]
|
||||
////
|
||||
////// function expressions
|
||||
////(function f()[| {
|
||||
////
|
||||
////}|])
|
||||
////
|
||||
////// trivia handeling
|
||||
////class ClassFooWithTrivia[| /* some comments */
|
||||
//// /* more trivia */ {
|
||||
////
|
||||
////
|
||||
//// /*some trailing trivia */
|
||||
////}|] /* even more */
|
||||
////
|
||||
////// object literals
|
||||
////var x =[|{
|
||||
//// a:1,
|
||||
//// b:2,
|
||||
//// get foo()[| {
|
||||
//// return 1;
|
||||
//// }|]
|
||||
////}|]
|
||||
//////outline with deep nesting
|
||||
////module m1[|{
|
||||
//// module m2[| {
|
||||
//// module m3[| {
|
||||
//// module m4[| {
|
||||
//// module m5[| {
|
||||
//// module m6[| {
|
||||
//// module m7[| {
|
||||
//// module m8[| {
|
||||
//// module m9[| {
|
||||
//// module m10[| {
|
||||
//// module m11 {
|
||||
//// module m12 {
|
||||
//// export interface IFoo {
|
||||
//// }
|
||||
//// }
|
||||
//// }
|
||||
//// }|]
|
||||
//// }|]
|
||||
//// }|]
|
||||
//// }|]
|
||||
//// }|]
|
||||
//// }|]
|
||||
//// }|]
|
||||
//// }|]
|
||||
//// }|]
|
||||
////}|]
|
||||
////
|
||||
//////outline after a deeply nested node
|
||||
////class AfterNestedNodes[| {
|
||||
////}|]
|
||||
|
||||
verify.outliningSpansInCurrentFile(test.ranges());
|
||||
@@ -0,0 +1,32 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: refFile1.ts
|
||||
//// class D { }
|
||||
|
||||
// @Filename: refFile2.ts
|
||||
//// export class E {}
|
||||
|
||||
// @Filename: main.ts
|
||||
// @ResolveReference: true
|
||||
//// ///<reference path="refFile1.ts" />
|
||||
//// /*1*////<reference path = "NotExistRef.ts" />/*2*/
|
||||
//// /*3*////<reference path "invalidRefFile1.ts" />/*4*/
|
||||
//// import ref2 = require("refFile2");
|
||||
//// import noExistref2 = require(/*5*/"NotExistRefFile2"/*6*/);
|
||||
//// import invalidRef1 /*7*/require/*8*/("refFile2");
|
||||
//// /*9*/import invalidRef2 = requi/*10*/("refFile2");
|
||||
//// var obj: /*11*/C/*12*/;
|
||||
//// var obj1: D;
|
||||
//// var obj2: ref2.E;
|
||||
|
||||
goTo.file("main.ts");
|
||||
verify.numberOfErrorsInCurrentFile(7);
|
||||
verify.errorExistsBetweenMarkers("1", "2");
|
||||
verify.errorExistsBetweenMarkers("3", "4");
|
||||
verify.errorExistsBetweenMarkers("5", "6");
|
||||
verify.errorExistsBetweenMarkers("7", "8");
|
||||
verify.errorExistsBetweenMarkers("9", "10"); // At this position, there are two diagnostic messages: ';' expected, Cannot find name 'requi'
|
||||
verify.errorExistsBetweenMarkers("11", "12");
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
////class SS<T>{}
|
||||
////
|
||||
////var x/*1*/1 = new SS<number>();
|
||||
////var x/*2*/2 = new SS();
|
||||
////var x/*3*/3 = new SS;
|
||||
|
||||
goTo.marker('1');
|
||||
verify.quickInfoIs('(var) x1: SS<number>');
|
||||
|
||||
goTo.marker('2');
|
||||
verify.quickInfoIs('(var) x2: SS<{}>');
|
||||
|
||||
goTo.marker('3');
|
||||
verify.quickInfoIs('(var) x3: SS<{}>');
|
||||
@@ -0,0 +1,29 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//@Filename: findAllRefsOnDefinition-import.ts
|
||||
////export class Test{
|
||||
////
|
||||
//// constructor(){
|
||||
////
|
||||
//// }
|
||||
////
|
||||
//// public /*1*/start(){
|
||||
//// return this;
|
||||
//// }
|
||||
////
|
||||
//// public stop(){
|
||||
//// return this;
|
||||
//// }
|
||||
////}
|
||||
|
||||
//@Filename: findAllRefsOnDefinition.ts
|
||||
////import Second = require("findAllRefsOnDefinition-import");
|
||||
////
|
||||
////var second = new Second.Test()
|
||||
////second.start();
|
||||
////second.stop();
|
||||
|
||||
goTo.file("findAllRefsOnDefinition-import.ts");
|
||||
goTo.marker("1");
|
||||
|
||||
verify.referencesCountIs(2);
|
||||
@@ -0,0 +1,11 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
///////<reference path="./Bar.ts" />
|
||||
|
||||
////function /**/[|Bar|]() {
|
||||
//// // This is a reference to Bar in a comment.
|
||||
//// "this is a reference to Bar in a string"
|
||||
////}
|
||||
|
||||
goTo.marker();
|
||||
verify.renameLocations(/*findInStrings:*/ false, /*findInComments:*/ false);
|
||||
@@ -0,0 +1,15 @@
|
||||
/// <reference path="fourslash.ts"/>
|
||||
|
||||
//// module /*0*/M {
|
||||
//// export interface /*1*/I {
|
||||
//// }
|
||||
//// }
|
||||
//// interface /*2*/X extends /*3*/M./*4*/I { }
|
||||
|
||||
var c = classification;
|
||||
verify.semanticClassificationsAre(
|
||||
c.moduleName("M", test.marker("0").position),
|
||||
c.interfaceName("I", test.marker("1").position),
|
||||
c.interfaceName("X", test.marker("2").position),
|
||||
c.moduleName("M", test.marker("3").position),
|
||||
c.interfaceName("I", test.marker("4").position));
|
||||
@@ -0,0 +1,11 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @module: CommonJS
|
||||
// @declaration: true
|
||||
//// interface privateInterface {}
|
||||
//// export class Bar implements /*1*/privateInterface/*2*/{ }
|
||||
|
||||
verify.errorExistsBetweenMarkers("1", "2");
|
||||
verify.numberOfErrorsInCurrentFile(1);
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @Filename: signatureHelpInFunctionCallOnFunctionDeclarationInMultipleFiles_file0.ts
|
||||
////declare function fn(x: string, y: number);
|
||||
|
||||
// @Filename: signatureHelpInFunctionCallOnFunctionDeclarationInMultipleFiles_file1.ts
|
||||
////declare function fn(x: string);
|
||||
|
||||
// @Filename: signatureHelpInFunctionCallOnFunctionDeclarationInMultipleFiles_file2.ts
|
||||
////fn(/*1*/
|
||||
|
||||
goTo.marker('1');
|
||||
verify.signatureHelpCountIs(2);
|
||||
@@ -0,0 +1,35 @@
|
||||
/// <reference path="fourslash.ts"/>
|
||||
|
||||
//// // comment
|
||||
//// module M {
|
||||
//// var v = 0 + 1;
|
||||
//// var s = "string";
|
||||
////
|
||||
//// class C<T> {
|
||||
//// }
|
||||
////
|
||||
//// enum E {
|
||||
//// }
|
||||
////
|
||||
//// interface I {
|
||||
//// }
|
||||
////
|
||||
//// module M1.M2 {
|
||||
//// }
|
||||
//// }
|
||||
|
||||
var c = classification;
|
||||
verify.syntacticClassificationsAre(
|
||||
c.comment("// comment"),
|
||||
c.keyword("module"), c.moduleName("M"), c.punctuation("{"),
|
||||
c.keyword("var"), c.text("v"), c.operator("="), c.numericLiteral("0"), c.operator("+"), c.numericLiteral("1"), c.punctuation(";"),
|
||||
c.keyword("var"), c.text("s"), c.operator("="), c.stringLiteral('"string"'), c.punctuation(";"),
|
||||
c.keyword("class"), c.className("C"), c.punctuation("<"), c.typeParameterName("T"), c.punctuation(">"), c.punctuation("{"),
|
||||
c.punctuation("}"),
|
||||
c.keyword("enum"), c.enumName("E"), c.punctuation("{"),
|
||||
c.punctuation("}"),
|
||||
c.keyword("interface"), c.interfaceName("I"), c.punctuation("{"),
|
||||
c.punctuation("}"),
|
||||
c.keyword("module"), c.moduleName("M1"), c.punctuation("."), c.moduleName("M2"), c.punctuation("{"),
|
||||
c.punctuation("}"),
|
||||
c.punctuation("}"));
|
||||
@@ -0,0 +1,3 @@
|
||||
//// // [|TODO|]
|
||||
|
||||
verify.todoCommentsInCurrentFile(["TODO"]);
|
||||
@@ -0,0 +1,76 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
////var /*1*/a = 10;
|
||||
////function foo() {
|
||||
//// var /*2*/b = /*3*/a;
|
||||
////}
|
||||
////module m {
|
||||
//// var /*4*/c = 10;
|
||||
//// export var /*5*/d = 10;
|
||||
////}
|
||||
////var /*6*/f: () => number;
|
||||
////var /*7*/g = /*8*/f;
|
||||
/////*9*/f();
|
||||
////var /*10*/h: { (a: string): number; (a: number): string; };
|
||||
////var /*11*/i = /*12*/h;
|
||||
/////*13*/h(10);
|
||||
/////*14*/h("hello");
|
||||
|
||||
var marker = 0;
|
||||
function verifyVar(name: string, isLocal: boolean, typeDisplay: ts.SymbolDisplayPart[], optionalNameDisplay?: ts.SymbolDisplayPart[], optionalKindModifiers?: string) {
|
||||
marker++;
|
||||
goTo.marker(marker.toString());
|
||||
var kind = isLocal ? "local var" : "var";
|
||||
verify.verifyQuickInfoDisplayParts(kind, optionalKindModifiers || "", { start: test.markerByName(marker.toString()).position, length: name.length },
|
||||
[{ text: "(", kind: "punctuation" }, { text: kind, kind: "text" }, { text: ")", kind: "punctuation" },
|
||||
{ text: " ", kind: "space" }].concat(optionalNameDisplay || [{ text: name, kind: "localName" }]).concat(
|
||||
{ text: ":", kind: "punctuation" }, { text: " ", kind: "space" }).concat(typeDisplay),
|
||||
[]);
|
||||
}
|
||||
|
||||
var numberTypeDisplay: ts.SymbolDisplayPart[] = [{ text: "number", kind: "keyword" }];
|
||||
|
||||
verifyVar("a", /*isLocal*/false, numberTypeDisplay);
|
||||
verifyVar("b", /*isLocal*/true, numberTypeDisplay);
|
||||
verifyVar("a", /*isLocal*/false, numberTypeDisplay);
|
||||
verifyVar("c", /*isLocal*/false, numberTypeDisplay);
|
||||
verifyVar("d", /*isLocal*/false, numberTypeDisplay, [{ text: "m", kind: "moduleName" }, { text: ".", kind: "punctuation" }, { text: "d", kind: "localName" }], "export");
|
||||
|
||||
var functionTypeReturningNumber: ts.SymbolDisplayPart[] = [{ text: "(", kind: "punctuation" }, { text: ")", kind: "punctuation" },
|
||||
{ text: " ", kind: "space" }, { text: "=>", kind: "punctuation" }, { text: " ", kind: "space" }, { text: "number", kind: "keyword" }];
|
||||
verifyVar("f", /*isLocal*/ false, functionTypeReturningNumber);
|
||||
verifyVar("g", /*isLocal*/ false, functionTypeReturningNumber);
|
||||
verifyVar("f", /*isLocal*/ false, functionTypeReturningNumber);
|
||||
verifyVar("f", /*isLocal*/ false, functionTypeReturningNumber);
|
||||
|
||||
|
||||
function getFunctionType(parametertype: string, returnType: string, isArrow?: boolean): ts.SymbolDisplayPart[] {
|
||||
var functionTypeDisplay = [{ text: "(", kind: "punctuation" }, { text: "a", kind: "parameterName" }, { text: ":", kind: "punctuation" },
|
||||
{ text: " ", kind: "space" }, { text: parametertype, kind: "keyword" }, { text: ")", kind: "punctuation" }];
|
||||
|
||||
if (isArrow) {
|
||||
functionTypeDisplay = functionTypeDisplay.concat({ text: " ", kind: "space" }, { text: "=>", kind: "punctuation" });
|
||||
}
|
||||
else {
|
||||
functionTypeDisplay = functionTypeDisplay.concat({ text: ":", kind: "punctuation" });
|
||||
}
|
||||
|
||||
return functionTypeDisplay.concat({ text: " ", kind: "space" }, { text: returnType, kind: "keyword" });
|
||||
}
|
||||
|
||||
var typeLiteralWithOverloadCall: ts.SymbolDisplayPart[] = [{ text: "{", kind: "punctuation" }, { text: "\n", kind: "lineBreak" },
|
||||
{ text: " ", kind: "space" }].concat(getFunctionType("string", "number")).concat(
|
||||
{ text: ";", kind: "punctuation" }, { text: "\n", kind: "lineBreak" },
|
||||
{ text: " ", kind: "space" }).concat(getFunctionType("number", "string")).concat(
|
||||
{ text: ";", kind: "punctuation" }, { text: "\n", kind: "lineBreak" }, { text: "}", kind: "punctuation" });
|
||||
|
||||
verifyVar("h", /*isLocal*/ false, typeLiteralWithOverloadCall);
|
||||
verifyVar("i", /*isLocal*/ false, typeLiteralWithOverloadCall);
|
||||
verifyVar("h", /*isLocal*/ false, typeLiteralWithOverloadCall);
|
||||
|
||||
var overloadDisplay: ts.SymbolDisplayPart[] = [{ text: " ", kind: "space" }, { text: "(", kind: "punctuation" },
|
||||
{ text: "+", kind: "operator" }, { text: "1", kind: "numericLiteral" },
|
||||
{ text: " ", kind: "space" }, { text: "overload", kind: "text" }, { text: ")", kind: "punctuation" }];
|
||||
|
||||
verifyVar("h", /*isLocal*/ false, getFunctionType("number", "string", /*isArrow*/true).concat(overloadDisplay));
|
||||
verifyVar("h", /*isLocal*/ false, getFunctionType("string", "number", /*isArrow*/true).concat(overloadDisplay));
|
||||
@@ -20,5 +20,3 @@ edit.insert(", X");
|
||||
goTo.marker('addTypeParam');
|
||||
|
||||
edit.insert(", X");
|
||||
|
||||
diagnostics.validateTypesAtPositions(91, 163);
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//// class Point {
|
||||
////
|
||||
//// constructor(public x: number) {
|
||||
////
|
||||
//// }
|
||||
//// getDist() {
|
||||
//// }
|
||||
//// static origin = new Point(0);
|
||||
//// }
|
||||
////
|
||||
//// class Point3D {
|
||||
////
|
||||
//// constructor(x: number, y: number, private z) {
|
||||
//// super(x, y);
|
||||
//// }
|
||||
////
|
||||
//// getDist() {
|
||||
//// return Math.sqrt(this.x*this.x + this.z*this.m);
|
||||
//// }
|
||||
//// }
|
||||
////
|
||||
////
|
||||
|
||||
edit.disableFormatting();
|
||||
diagnostics.validateTypesAtPositions(258);
|
||||
@@ -1,12 +0,0 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//// interface Sequence<T> {
|
||||
//// each(iterator: (value: T) => void): void;
|
||||
//// filter(): Sequence<T>;
|
||||
//// groupBy<K>(keySelector: () => K): Sequence<{ items: T/**/[]; }>;
|
||||
//// }
|
||||
|
||||
goTo.file(0);
|
||||
|
||||
// Marker in above file is placed at position 154
|
||||
diagnostics.validateTypesAtPositions(154);
|
||||
@@ -1,11 +0,0 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//// function method() {
|
||||
//// var dictionary = <{ [index: string]: string; }>{};
|
||||
//// }
|
||||
////
|
||||
|
||||
edit.disableFormatting(); // Disregard, just here to keep Fourslash happy
|
||||
|
||||
diagnostics.validateTypesAtPositions(44);
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
//// // @sourcemap: true
|
||||
//// module Foo.Bar {
|
||||
//// "use strict";
|
||||
////
|
||||
//// class Greeter {
|
||||
//// constructor(public greeting: string) {
|
||||
//// }
|
||||
////
|
||||
//// greet() {
|
||||
//// }
|
||||
//// }
|
||||
////
|
||||
////
|
||||
//// function foo(greeting: string): Foo.Bar.Greeter {
|
||||
//// return new Greeter(greeting);
|
||||
//// }
|
||||
////
|
||||
//// var greeter = new Greeter("Hello, world!");
|
||||
//// var str = greeter.greet();
|
||||
////
|
||||
//// function foo2(greeting: string, ...restGreetings) {
|
||||
//// var greeters: Greeter[] = [];
|
||||
//// new Greeter(greeting);
|
||||
//// for (var i = 0; restGreetings.length; i++) {
|
||||
//// greeters.push(new Greeter(restGreetings[i]));
|
||||
//// }
|
||||
////
|
||||
//// return greeters;
|
||||
//// }
|
||||
////
|
||||
//// var b = foo2("Hello", "World");
|
||||
//// for (var j = 0; j < b.length; j++) {
|
||||
//// b[j].greet();
|
||||
//// }
|
||||
//// }
|
||||
|
||||
edit.disableFormatting();
|
||||
diagnostics.validateTypesAtPositions(705);
|
||||
@@ -1,84 +1,47 @@
|
||||
/// <reference path="..\..\..\..\src\harness\external\mocha.d.ts" />
|
||||
/// <reference path="..\..\..\..\src\harness\harnessLanguageService.ts" />
|
||||
|
||||
interface Classification {
|
||||
position: number;
|
||||
length: number;
|
||||
class: ts.TokenClass;
|
||||
}
|
||||
|
||||
interface ClassiferResult {
|
||||
tuples: Classification[];
|
||||
finalEndOfLineState: ts.EndOfLineState;
|
||||
}
|
||||
|
||||
interface ClassificationEntry {
|
||||
value: any;
|
||||
class: ts.TokenClass;
|
||||
classification: ts.TokenClass;
|
||||
}
|
||||
|
||||
describe('Colorization', function () {
|
||||
var mytypescriptLS = new Harness.LanguageService.TypeScriptLS();
|
||||
var myclassifier = mytypescriptLS.getClassifier();
|
||||
// Use the shim adapter to ensure test coverage of the shim layer for the classifier
|
||||
var languageServiceAdabtor = new Harness.LanguageService.ShimLanugageServiceAdapter();
|
||||
var classifier = languageServiceAdabtor.getClassifier();
|
||||
|
||||
function getLexicalClassifications(code: string, initialEndOfLineState: ts.EndOfLineState = ts.EndOfLineState.Start): ClassiferResult {
|
||||
var classResult = myclassifier.getClassificationsForLine(code, initialEndOfLineState).split('\n');
|
||||
var tuples: Classification[] = [];
|
||||
var i = 0;
|
||||
var position = 0;
|
||||
|
||||
for (; i < classResult.length - 1; i += 2) {
|
||||
var t = tuples[i / 2] = {
|
||||
position: position,
|
||||
length: parseInt(classResult[i]),
|
||||
class: parseInt(classResult[i + 1])
|
||||
};
|
||||
|
||||
assert.isTrue(t.length > 0, "Result length should be greater than 0, got :" + t.length);
|
||||
position += t.length;
|
||||
}
|
||||
var finalEndOfLineState = classResult[classResult.length - 1];
|
||||
|
||||
assert.equal(position, code.length, "Expected cumulative length of all entries to match the length of the source. expected: " + code.length + ", but got: " + position);
|
||||
|
||||
return {
|
||||
tuples: tuples,
|
||||
finalEndOfLineState: parseInt(finalEndOfLineState)
|
||||
};
|
||||
}
|
||||
|
||||
function verifyClassification(classification: Classification, expectedLength: number, expectedClass: number) {
|
||||
assert.isNotNull(classification);
|
||||
assert.equal(classification.length, expectedLength, "Classification length does not match expected. Expected: " + expectedLength + ", Actual: " + classification.length);
|
||||
assert.equal(classification.class, expectedClass, "Classification class does not match expected. Expected: " + ts.TokenClass[expectedClass] + ", Actual: " + ts.TokenClass[classification.class]);
|
||||
}
|
||||
|
||||
function getEntryAtPosistion(result: ClassiferResult, position: number) {
|
||||
for (var i = 0, n = result.tuples.length; i < n; i++) {
|
||||
if (result.tuples[i].position === position) return result.tuples[i];
|
||||
function getEntryAtPosistion(result: ts.ClassificationResult, position: number) {
|
||||
var entryPosition = 0;
|
||||
for (var i = 0, n = result.entries.length; i < n; i++) {
|
||||
var entry = result.entries[i];
|
||||
if (entryPosition === position) {
|
||||
return entry;
|
||||
}
|
||||
entryPosition += entry.length;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function punctuation(text: string) { return { value: text, class: ts.TokenClass.Punctuation }; }
|
||||
function keyword(text: string) { return { value: text, class: ts.TokenClass.Keyword }; }
|
||||
function operator(text: string) { return { value: text, class: ts.TokenClass.Operator }; }
|
||||
function comment(text: string) { return { value: text, class: ts.TokenClass.Comment }; }
|
||||
function whitespace(text: string) { return { value: text, class: ts.TokenClass.Whitespace }; }
|
||||
function identifier(text: string) { return { value: text, class: ts.TokenClass.Identifier }; }
|
||||
function numberLiteral(text: string) { return { value: text, class: ts.TokenClass.NumberLiteral }; }
|
||||
function stringLiteral(text: string) { return { value: text, class: ts.TokenClass.StringLiteral }; }
|
||||
function regExpLiteral(text: string) { return { value: text, class: ts.TokenClass.RegExpLiteral }; }
|
||||
function finalEndOfLineState(value: number) { return { value: value, class: <ts.TokenClass>undefined }; }
|
||||
function punctuation(text: string): ClassificationEntry { return { value: text, classification: ts.TokenClass.Punctuation }; }
|
||||
function keyword(text: string): ClassificationEntry { return { value: text, classification: ts.TokenClass.Keyword }; }
|
||||
function operator(text: string): ClassificationEntry { return { value: text, classification: ts.TokenClass.Operator }; }
|
||||
function comment(text: string): ClassificationEntry { return { value: text, classification: ts.TokenClass.Comment }; }
|
||||
function whitespace(text: string): ClassificationEntry { return { value: text, classification: ts.TokenClass.Whitespace }; }
|
||||
function identifier(text: string): ClassificationEntry { return { value: text, classification: ts.TokenClass.Identifier }; }
|
||||
function numberLiteral(text: string): ClassificationEntry { return { value: text, classification: ts.TokenClass.NumberLiteral }; }
|
||||
function stringLiteral(text: string): ClassificationEntry { return { value: text, classification: ts.TokenClass.StringLiteral }; }
|
||||
function regExpLiteral(text: string): ClassificationEntry { return { value: text, classification: ts.TokenClass.RegExpLiteral }; }
|
||||
function finalEndOfLineState(value: number): ClassificationEntry { return { value: value, classification: <ts.TokenClass>undefined }; }
|
||||
|
||||
function testLexicalClassification(text: string, initialEndOfLineState: ts.EndOfLineState, ...expectedEntries: ClassificationEntry[]): void {
|
||||
var result = getLexicalClassifications(text, initialEndOfLineState);
|
||||
var result = classifier.getClassificationsForLine(text, initialEndOfLineState);
|
||||
|
||||
for (var i = 0, n = expectedEntries.length; i < n; i++) {
|
||||
var expectedEntry = expectedEntries[i];
|
||||
|
||||
if (expectedEntry.class === undefined) {
|
||||
assert.equal(result.finalEndOfLineState, expectedEntry.value, "final endOfLineState does not match expected.");
|
||||
if (expectedEntry.classification === undefined) {
|
||||
assert.equal(result.finalLexState, expectedEntry.value, "final endOfLineState does not match expected.");
|
||||
}
|
||||
else {
|
||||
var actualEntryPosition = text.indexOf(expectedEntry.value);
|
||||
@@ -87,7 +50,7 @@ describe('Colorization', function () {
|
||||
var actualEntry = getEntryAtPosistion(result, actualEntryPosition);
|
||||
|
||||
assert(actualEntry, "Could not find classification entry for '" + expectedEntry.value + "' at position: " + actualEntryPosition);
|
||||
assert.equal(actualEntry.class, expectedEntry.class, "Classification class does not match expected. Expected: " + ts.TokenClass[expectedEntry.class] + ", Actual: " + ts.TokenClass[actualEntry.class]);
|
||||
assert.equal(actualEntry.classification, expectedEntry.classification, "Classification class does not match expected. Expected: " + ts.TokenClass[expectedEntry.classification] + ", Actual: " + ts.TokenClass[actualEntry.classification]);
|
||||
assert.equal(actualEntry.length, expectedEntry.value.length, "Classification length does not match expected. Expected: " + ts.TokenClass[expectedEntry.value.length] + ", Actual: " + ts.TokenClass[actualEntry.length]);
|
||||
}
|
||||
}
|
||||
@@ -320,8 +283,6 @@ describe('Colorization', function () {
|
||||
});
|
||||
|
||||
it("LexicallyClassifiesConflictTokens", () => {
|
||||
debugger;
|
||||
|
||||
// Test conflict markers.
|
||||
testLexicalClassification(
|
||||
"class C {\r\n\
|
||||
|
||||
Reference in New Issue
Block a user