Merge branch 'master' into rootDir

Conflicts:
	tests/baselines/reference/APISample_compile.types
	tests/baselines/reference/APISample_linter.types
	tests/baselines/reference/APISample_transform.types
	tests/baselines/reference/APISample_watcher.types
This commit is contained in:
Mohamed Hegazy
2015-04-16 16:52:51 -07:00
5195 changed files with 249167 additions and 91341 deletions
+116 -51
View File
@@ -2197,25 +2197,7 @@ module ts {
}
else if (hasSpreadElement) {
let unionOfElements = getUnionType(elementTypes);
if (languageVersion >= ScriptTarget.ES6) {
// If the user has something like:
//
// function fun(...[a, ...b]) { }
//
// Normally, in ES6, the implied type of an array binding pattern with a rest element is
// an iterable. However, there is a requirement in our type system that all rest
// parameters be array types. To satisfy this, we have an exception to the rule that
// says the type of an array binding pattern with a rest element is an array type
// if it is *itself* in a rest parameter. It will still be compatible with a spreaded
// iterable argument, but within the function it will be an array.
let parent = pattern.parent;
let isRestParameter = parent.kind === SyntaxKind.Parameter &&
pattern === (<ParameterDeclaration>parent).name &&
(<ParameterDeclaration>parent).dotDotDotToken !== undefined;
return isRestParameter ? createArrayType(unionOfElements) : createIterableType(unionOfElements);
}
return createArrayType(unionOfElements);
return languageVersion >= ScriptTarget.ES6 ? createIterableType(unionOfElements) : createArrayType(unionOfElements);
}
// If the pattern has at least one element, and no rest element, then it should imply a tuple type.
@@ -4016,6 +3998,7 @@ module ts {
if (source === numberType && target.flags & TypeFlags.Enum) return Ternary.True;
}
}
let saveErrorInfo = errorInfo;
if (source.flags & TypeFlags.Union || target.flags & TypeFlags.Union) {
if (relation === identityRelation) {
if (source.flags & TypeFlags.Union && target.flags & TypeFlags.Union) {
@@ -4054,25 +4037,34 @@ module ts {
return result;
}
}
else {
let saveErrorInfo = errorInfo;
if (source.flags & TypeFlags.Reference && target.flags & TypeFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target) {
// We have type references to same target type, see if relationship holds for all type arguments
if (result = typesRelatedTo((<TypeReference>source).typeArguments, (<TypeReference>target).typeArguments, reportErrors)) {
return result;
}
else if (source.flags & TypeFlags.Reference && target.flags & TypeFlags.Reference && (<TypeReference>source).target === (<TypeReference>target).target) {
// We have type references to same target type, see if relationship holds for all type arguments
if (result = typesRelatedTo((<TypeReference>source).typeArguments, (<TypeReference>target).typeArguments, reportErrors)) {
return result;
}
// Even if relationship doesn't hold for type arguments, it may hold in a structural comparison
// Report structural errors only if we haven't reported any errors yet
let reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo;
// identity relation does not use apparent type
let sourceOrApparentType = relation === identityRelation ? source : getApparentType(source);
if (sourceOrApparentType.flags & TypeFlags.ObjectType && target.flags & TypeFlags.ObjectType &&
(result = objectTypeRelatedTo(sourceOrApparentType, <ObjectType>target, reportStructuralErrors))) {
}
// Even if relationship doesn't hold for unions, type parameters, or generic type references,
// it may hold in a structural comparison.
// Report structural errors only if we haven't reported any errors yet
let reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo;
// identity relation does not use apparent type
let sourceOrApparentType = relation === identityRelation ? source : getApparentType(source);
if (sourceOrApparentType.flags & TypeFlags.ObjectType && target.flags & TypeFlags.ObjectType) {
if (result = objectTypeRelatedTo(sourceOrApparentType, <ObjectType>target, reportStructuralErrors)) {
errorInfo = saveErrorInfo;
return result;
}
}
else if (source.flags & TypeFlags.TypeParameter && sourceOrApparentType.flags & TypeFlags.Union) {
// We clear the errors first because the following check often gives a better error than
// the union comparison above if it is applicable.
errorInfo = saveErrorInfo;
if (result = isRelatedTo(sourceOrApparentType, target, reportErrors)) {
return result;
}
}
if (reportErrors) {
headMessage = headMessage || Diagnostics.Type_0_is_not_assignable_to_type_1;
let sourceType = typeToString(source);
@@ -5412,8 +5404,8 @@ module ts {
// will be bound to non-arrow function that contain this arrow function. This results in inconsistent behavior.
// To avoid that we will give an error to users if they use arguments objects in arrow function so that they
// can explicitly bound arguments objects
if (symbol === argumentsSymbol && getContainingFunction(node).kind === SyntaxKind.ArrowFunction) {
error(node, Diagnostics.The_arguments_object_cannot_be_referenced_in_an_arrow_function_Consider_using_a_standard_function_expression);
if (symbol === argumentsSymbol && getContainingFunction(node).kind === SyntaxKind.ArrowFunction && languageVersion < ScriptTarget.ES6) {
error(node, Diagnostics.The_arguments_object_cannot_be_referenced_in_an_arrow_function_in_ES3_and_ES5_Consider_using_a_standard_function_expression);
}
if (symbol.flags & SymbolFlags.Alias && !isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(resolveAlias(symbol))) {
@@ -6025,14 +6017,38 @@ module ts {
}
let hasSpreadElement = false;
let elementTypes: Type[] = [];
let inDestructuringPattern = isAssignmentTarget(node);
for (let e of elements) {
let type = checkExpression(e, contextualMapper);
elementTypes.push(type);
if (inDestructuringPattern && e.kind === SyntaxKind.SpreadElementExpression) {
// Given the following situation:
// var c: {};
// [...c] = ["", 0];
//
// c is represented in the tree as a spread element in an array literal.
// But c really functions as a rest element, and its purpose is to provide
// a contextual type for the right hand side of the assignment. Therefore,
// instead of calling checkExpression on "...c", which will give an error
// if c is not iterable/array-like, we need to act as if we are trying to
// get the contextual element type from it. So we do something similar to
// getContextualTypeForElementExpression, which will crucially not error
// if there is no index type / iterated type.
let restArrayType = checkExpression((<SpreadElementExpression>e).expression, contextualMapper);
let restElementType = getIndexTypeOfType(restArrayType, IndexKind.Number) ||
(languageVersion >= ScriptTarget.ES6 ? checkIteratedType(restArrayType, /*expressionForError*/ undefined) : undefined);
if (restElementType) {
elementTypes.push(restElementType);
}
}
else {
let type = checkExpression(e, contextualMapper);
elementTypes.push(type);
}
hasSpreadElement = hasSpreadElement || e.kind === SyntaxKind.SpreadElementExpression;
}
if (!hasSpreadElement) {
let contextualType = getContextualType(node);
if (contextualType && contextualTypeIsTupleLikeType(contextualType) || isAssignmentTarget(node)) {
if (contextualType && contextualTypeIsTupleLikeType(contextualType) || inDestructuringPattern) {
return createTupleType(elementTypes);
}
}
@@ -7623,7 +7639,7 @@ module ts {
// This elementType will be used if the specific property corresponding to this index is not
// present (aka the tuple element property). This call also checks that the parentType is in
// fact an iterable or array (depending on target language).
let elementType = checkIteratedTypeOrElementType(sourceType, node, /*allowStringInput*/ false);
let elementType = checkIteratedTypeOrElementType(sourceType, node, /*allowStringInput*/ false) || unknownType;
let elements = node.elements;
for (let i = 0; i < elements.length; i++) {
let e = elements[i];
@@ -7647,11 +7663,17 @@ module ts {
}
}
else {
if (i === elements.length - 1) {
checkReferenceAssignment((<SpreadElementExpression>e).expression, createArrayType(elementType), contextualMapper);
if (i < elements.length - 1) {
error(e, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern);
}
else {
error(e, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern);
let restExpression = (<SpreadElementExpression>e).expression;
if (restExpression.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>restExpression).operatorToken.kind === SyntaxKind.EqualsToken) {
error((<BinaryExpression>restExpression).operatorToken, Diagnostics.A_rest_element_cannot_have_an_initializer);
}
else {
checkDestructuringAssignment(restExpression, createArrayType(elementType), contextualMapper);
}
}
}
}
@@ -8111,10 +8133,11 @@ module ts {
if (node.questionToken && isBindingPattern(node.name) && func.body) {
error(node, Diagnostics.A_binding_pattern_parameter_cannot_be_optional_in_an_implementation_signature);
}
if (node.dotDotDotToken) {
if (!isArrayType(getTypeOfSymbol(node.symbol))) {
error(node, Diagnostics.A_rest_parameter_must_be_of_an_array_type);
}
// Only check rest parameter type if it's not a binding pattern. Since binding patterns are
// not allowed in a rest parameter, we already have an error from checkGrammarParameterList.
if (node.dotDotDotToken && !isBindingPattern(node.name) && !isArrayType(getTypeOfSymbol(node.symbol))) {
error(node, Diagnostics.A_rest_parameter_must_be_of_an_array_type);
}
}
@@ -9417,6 +9440,10 @@ module ts {
}
function checkIteratedTypeOrElementType(inputType: Type, errorNode: Node, allowStringInput: boolean): Type {
if (inputType.flags & TypeFlags.Any) {
return inputType;
}
if (languageVersion >= ScriptTarget.ES6) {
return checkIteratedType(inputType, errorNode) || anyType;
}
@@ -10407,13 +10434,29 @@ module ts {
function getFirstNonAmbientClassOrFunctionDeclaration(symbol: Symbol): Declaration {
let declarations = symbol.declarations;
for (let declaration of declarations) {
if ((declaration.kind === SyntaxKind.ClassDeclaration || (declaration.kind === SyntaxKind.FunctionDeclaration && nodeIsPresent((<FunctionLikeDeclaration>declaration).body))) && !isInAmbientContext(declaration)) {
if ((declaration.kind === SyntaxKind.ClassDeclaration ||
(declaration.kind === SyntaxKind.FunctionDeclaration && nodeIsPresent((<FunctionLikeDeclaration>declaration).body))) &&
!isInAmbientContext(declaration)) {
return declaration;
}
}
return undefined;
}
function inSameLexicalScope(node1: Node, node2: Node) {
let container1 = getEnclosingBlockScopeContainer(node1);
let container2 = getEnclosingBlockScopeContainer(node2);
if (isGlobalSourceFile(container1)) {
return isGlobalSourceFile(container2);
}
else if (isGlobalSourceFile(container2)) {
return false;
}
else {
return container1 === container2;
}
}
function checkModuleDeclaration(node: ModuleDeclaration) {
if (produceDiagnostics) {
// Grammar checking
@@ -10433,15 +10476,23 @@ module ts {
&& symbol.declarations.length > 1
&& !isInAmbientContext(node)
&& isInstantiatedModule(node, compilerOptions.preserveConstEnums || compilerOptions.separateCompilation)) {
let classOrFunc = getFirstNonAmbientClassOrFunctionDeclaration(symbol);
if (classOrFunc) {
if (getSourceFileOfNode(node) !== getSourceFileOfNode(classOrFunc)) {
let firstNonAmbientClassOrFunc = getFirstNonAmbientClassOrFunctionDeclaration(symbol);
if (firstNonAmbientClassOrFunc) {
if (getSourceFileOfNode(node) !== getSourceFileOfNode(firstNonAmbientClassOrFunc)) {
error(node.name, Diagnostics.A_module_declaration_cannot_be_in_a_different_file_from_a_class_or_function_with_which_it_is_merged);
}
else if (node.pos < classOrFunc.pos) {
else if (node.pos < firstNonAmbientClassOrFunc.pos) {
error(node.name, Diagnostics.A_module_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged);
}
}
// if the module merges with a class declaration in the same lexical scope,
// we need to track this to ensure the correct emit.
let mergedClass = getDeclarationOfKind(symbol, SyntaxKind.ClassDeclaration);
if (mergedClass &&
inSameLexicalScope(node, mergedClass)) {
getNodeLinks(node).flags |= NodeCheckFlags.LexicalModuleMergesWithClass;
}
}
// Checks for ambient external modules.
@@ -12260,6 +12311,10 @@ module ts {
return grammarErrorOnNode(parameter.dotDotDotToken, Diagnostics.A_rest_parameter_must_be_last_in_a_parameter_list);
}
if (isBindingPattern(parameter.name)) {
return grammarErrorOnNode(parameter.name, Diagnostics.A_rest_element_cannot_contain_a_binding_pattern);
}
if (parameter.questionToken) {
return grammarErrorOnNode(parameter.questionToken, Diagnostics.A_rest_parameter_cannot_be_optional);
}
@@ -12746,6 +12801,11 @@ module ts {
if (node !== elements[elements.length - 1]) {
return grammarErrorOnNode(node, Diagnostics.A_rest_element_must_be_last_in_an_array_destructuring_pattern);
}
if (node.name.kind === SyntaxKind.ArrayBindingPattern || node.name.kind === SyntaxKind.ObjectBindingPattern) {
return grammarErrorOnNode(node.name, Diagnostics.A_rest_element_cannot_contain_a_binding_pattern);
}
if (node.initializer) {
// Error on equals token which immediate precedes the initializer
return grammarErrorAtPos(getSourceFileOfNode(node), node.initializer.pos - 1, 1, Diagnostics.A_rest_element_cannot_have_an_initializer);
@@ -12943,6 +13003,11 @@ module ts {
}
}
function isEvalOrArgumentsIdentifier(node: Node): boolean {
return node.kind === SyntaxKind.Identifier &&
((<Identifier>node).text === "eval" || (<Identifier>node).text === "arguments");
}
function checkGrammarConstructorTypeParameters(node: ConstructorDeclaration) {
if (node.typeParameters) {
return grammarErrorAtPos(getSourceFileOfNode(node), node.typeParameters.pos, node.typeParameters.end - node.typeParameters.pos, Diagnostics.Type_parameters_cannot_appear_on_a_constructor_declaration);
-4
View File
@@ -659,10 +659,6 @@ module ts {
"\u0085": "\\u0085" // nextLine
};
export function getDefaultLibFileName(options: CompilerOptions): string {
return options.target === ScriptTarget.ES6 ? "lib.es6.d.ts" : "lib.d.ts";
}
export interface ObjectAllocator {
getNodeConstructor(kind: SyntaxKind): new () => Node;
getSymbolConstructor(): new (flags: SymbolFlags, name: string) => Symbol;
@@ -358,11 +358,12 @@ module ts {
Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2: { code: 2493, category: DiagnosticCategory.Error, key: "Tuple type '{0}' with length '{1}' cannot be assigned to tuple with length '{2}'." },
Using_a_string_in_a_for_of_statement_is_only_supported_in_ECMAScript_5_and_higher: { code: 2494, category: DiagnosticCategory.Error, key: "Using a string in a 'for...of' statement is only supported in ECMAScript 5 and higher." },
Type_0_is_not_an_array_type_or_a_string_type: { code: 2495, category: DiagnosticCategory.Error, key: "Type '{0}' is not an array type or a string type." },
The_arguments_object_cannot_be_referenced_in_an_arrow_function_Consider_using_a_standard_function_expression: { code: 2496, category: DiagnosticCategory.Error, key: "The 'arguments' object cannot be referenced in an arrow function. Consider using a standard function expression." },
The_arguments_object_cannot_be_referenced_in_an_arrow_function_in_ES3_and_ES5_Consider_using_a_standard_function_expression: { code: 2496, category: DiagnosticCategory.Error, key: "The 'arguments' object cannot be referenced in an arrow function in ES3 and ES5. Consider using a standard function expression." },
External_module_0_resolves_to_a_non_module_entity_and_cannot_be_imported_using_this_construct: { code: 2497, category: DiagnosticCategory.Error, key: "External module '{0}' resolves to a non-module entity and cannot be imported using this construct." },
External_module_0_uses_export_and_cannot_be_used_with_export_Asterisk: { code: 2498, category: DiagnosticCategory.Error, key: "External module '{0}' uses 'export =' and cannot be used with 'export *'." },
An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments: { code: 2499, category: DiagnosticCategory.Error, key: "An interface can only extend an identifier/qualified-name with optional type arguments." },
A_class_can_only_implement_an_identifier_Slashqualified_name_with_optional_type_arguments: { code: 2500, category: DiagnosticCategory.Error, key: "A class can only implement an identifier/qualified-name with optional type arguments." },
A_rest_element_cannot_contain_a_binding_pattern: { code: 2501, category: DiagnosticCategory.Error, key: "A rest element cannot contain a binding pattern." },
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}'." },
+5 -1
View File
@@ -1419,7 +1419,7 @@
"category": "Error",
"code": 2495
},
"The 'arguments' object cannot be referenced in an arrow function. Consider using a standard function expression.": {
"The 'arguments' object cannot be referenced in an arrow function in ES3 and ES5. Consider using a standard function expression.": {
"category": "Error",
"code": 2496
},
@@ -1439,6 +1439,10 @@
"category": "Error",
"code": 2500
},
"A rest element cannot contain a binding pattern.": {
"category": "Error",
"code": 2501
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
+73 -61
View File
@@ -1589,23 +1589,40 @@ var __param = this.__param || function(index, decorator) { return function (targ
return result;
}
function createPropertyAccessExpression(expression: LeftHandSideExpression, name: Identifier): PropertyAccessExpression {
function createPropertyAccessExpression(expression: Expression, name: Identifier): PropertyAccessExpression {
let result = <PropertyAccessExpression>createSynthesizedNode(SyntaxKind.PropertyAccessExpression);
result.expression = expression;
result.expression = parenthesizeForAccess(expression);
result.dotToken = createSynthesizedNode(SyntaxKind.DotToken);
result.name = name;
return result;
}
}
function createElementAccessExpression(expression: LeftHandSideExpression, argumentExpression: Expression): ElementAccessExpression {
function createElementAccessExpression(expression: Expression, argumentExpression: Expression): ElementAccessExpression {
let result = <ElementAccessExpression>createSynthesizedNode(SyntaxKind.ElementAccessExpression);
result.expression = expression;
result.expression = parenthesizeForAccess(expression);
result.argumentExpression = argumentExpression;
return result;
}
function parenthesizeForAccess(expr: Expression): LeftHandSideExpression {
// isLeftHandSideExpression is almost the correct criterion for when it is not necessary
// to parenthesize the expression before a dot. The known exceptions are:
//
// NewExpression:
// new C.x -> not the same as (new C).x
// NumberLiteral
// 1.x -> not the same as (1).x
//
if (isLeftHandSideExpression(expr) && expr.kind !== SyntaxKind.NewExpression && expr.kind !== SyntaxKind.NumericLiteral) {
return <LeftHandSideExpression>expr;
}
let node = <ParenthesizedExpression>createSynthesizedNode(SyntaxKind.ParenthesizedExpression);
node.expression = expr;
return node;
}
function emitComputedPropertyName(node: ComputedPropertyName) {
write("[");
emitExpressionForPropertyName(node);
@@ -2276,7 +2293,7 @@ var __param = this.__param || function(index, decorator) { return function (targ
if (node.initializer.kind === SyntaxKind.ArrayLiteralExpression || node.initializer.kind === SyntaxKind.ObjectLiteralExpression) {
// This is a destructuring pattern, so call emitDestructuring instead of emit. Calling emit will not work, because it will cause
// the BinaryExpression to be passed in instead of the expression statement, which will cause emitDestructuring to crash.
emitDestructuring(assignmentExpression, /*isAssignmentExpressionStatement*/ true, /*value*/ undefined, /*locationForCheckingExistingName*/ node);
emitDestructuring(assignmentExpression, /*isAssignmentExpressionStatement*/ true, /*value*/ undefined);
}
else {
emitNodeWithoutSourceMap(assignmentExpression);
@@ -2480,16 +2497,7 @@ var __param = this.__param || function(index, decorator) { return function (targ
}
}
/**
* If the root has a chance of being a synthesized node, callers should also pass a value for
* lowestNonSynthesizedAncestor. This should be an ancestor of root, it should not be synthesized,
* and there should not be a lower ancestor that introduces a scope. This node will be used as the
* location for ensuring that temporary names are unique.
*/
function emitDestructuring(root: BinaryExpression | VariableDeclaration | ParameterDeclaration,
isAssignmentExpressionStatement: boolean,
value?: Expression,
lowestNonSynthesizedAncestor?: Node) {
function emitDestructuring(root: BinaryExpression | VariableDeclaration | ParameterDeclaration, isAssignmentExpressionStatement: boolean, value?: Expression) {
let emitCount = 0;
// An exported declaration is actually emitted as an assignment (to a property on the module object), so
// temporary variables in an exported declaration need to have real declarations elsewhere
@@ -2520,9 +2528,6 @@ var __param = this.__param || function(index, decorator) { return function (targ
function ensureIdentifier(expr: Expression): Expression {
if (expr.kind !== SyntaxKind.Identifier) {
// In case the root is a synthesized node, we need to pass lowestNonSynthesizedAncestor
// as the location for determining uniqueness of the variable we are about to
// generate.
let identifier = createTempVariable(TempFlags.Auto);
if (!isDeclaration) {
recordTempDeclaration(identifier);
@@ -2561,27 +2566,22 @@ var __param = this.__param || function(index, decorator) { return function (targ
return node;
}
function parenthesizeForAccess(expr: Expression): LeftHandSideExpression {
if (expr.kind === SyntaxKind.Identifier || expr.kind === SyntaxKind.PropertyAccessExpression || expr.kind === SyntaxKind.ElementAccessExpression) {
return <LeftHandSideExpression>expr;
}
let node = <ParenthesizedExpression>createSynthesizedNode(SyntaxKind.ParenthesizedExpression);
node.expression = expr;
return node;
}
function createPropertyAccess(object: Expression, propName: Identifier): Expression {
function createPropertyAccessForDestructuringProperty(object: Expression, propName: Identifier | LiteralExpression): Expression {
if (propName.kind !== SyntaxKind.Identifier) {
return createElementAccess(object, propName);
return createElementAccessExpression(object, propName);
}
return createPropertyAccessExpression(parenthesizeForAccess(object), propName);
return createPropertyAccessExpression(object, propName);
}
function createElementAccess(object: Expression, index: Expression): Expression {
let node = <ElementAccessExpression>createSynthesizedNode(SyntaxKind.ElementAccessExpression);
node.expression = parenthesizeForAccess(object);
node.argumentExpression = index;
return node;
function createSliceCall(value: Expression, sliceIndex: number): CallExpression {
let call = <CallExpression>createSynthesizedNode(SyntaxKind.CallExpression);
let sliceIdentifier = <Identifier>createSynthesizedNode(SyntaxKind.Identifier);
sliceIdentifier.text = "slice";
call.expression = createPropertyAccessExpression(value, sliceIdentifier);
call.arguments = <NodeArray<LiteralExpression>>createSynthesizedNodeArray();
call.arguments[0] = createNumericLiteral(sliceIndex);
return call;
}
function emitObjectLiteralAssignment(target: ObjectLiteralExpression, value: Expression) {
@@ -2594,8 +2594,8 @@ var __param = this.__param || function(index, decorator) { return function (targ
for (let p of properties) {
if (p.kind === SyntaxKind.PropertyAssignment || p.kind === SyntaxKind.ShorthandPropertyAssignment) {
// TODO(andersh): Computed property support
let propName = <Identifier>((<PropertyAssignment>p).name);
emitDestructuringAssignment((<PropertyAssignment>p).initializer || propName, createPropertyAccess(value, propName));
let propName = <Identifier | LiteralExpression>((<PropertyAssignment>p).name);
emitDestructuringAssignment((<PropertyAssignment>p).initializer || propName, createPropertyAccessForDestructuringProperty(value, propName));
}
}
}
@@ -2611,14 +2611,10 @@ var __param = this.__param || function(index, decorator) { return function (targ
let e = elements[i];
if (e.kind !== SyntaxKind.OmittedExpression) {
if (e.kind !== SyntaxKind.SpreadElementExpression) {
emitDestructuringAssignment(e, createElementAccess(value, createNumericLiteral(i)));
emitDestructuringAssignment(e, createElementAccessExpression(value, createNumericLiteral(i)));
}
else {
if (i === elements.length - 1) {
value = ensureIdentifier(value);
emitAssignment(<Identifier>(<SpreadElementExpression>e).expression, value);
write(".slice(" + i + ")");
}
else if (i === elements.length - 1) {
emitDestructuringAssignment((<SpreadElementExpression>e).expression, createSliceCall(value, i));
}
}
}
@@ -2682,19 +2678,15 @@ var __param = this.__param || function(index, decorator) { return function (targ
if (pattern.kind === SyntaxKind.ObjectBindingPattern) {
// Rewrite element to a declaration with an initializer that fetches property
let propName = element.propertyName || <Identifier>element.name;
emitBindingElement(element, createPropertyAccess(value, propName));
emitBindingElement(element, createPropertyAccessForDestructuringProperty(value, propName));
}
else if (element.kind !== SyntaxKind.OmittedExpression) {
if (!element.dotDotDotToken) {
// Rewrite element to a declaration that accesses array element at index i
emitBindingElement(element, createElementAccess(value, createNumericLiteral(i)));
emitBindingElement(element, createElementAccessExpression(value, createNumericLiteral(i)));
}
else {
if (i === elements.length - 1) {
value = ensureIdentifier(value);
emitAssignment(<Identifier>element.name, value);
write(".slice(" + i + ")");
}
else if (i === elements.length - 1) {
emitBindingElement(element, createSliceCall(value, i));
}
}
}
@@ -2862,6 +2854,12 @@ var __param = this.__param || function(index, decorator) { return function (targ
if (languageVersion < ScriptTarget.ES6) {
let tempIndex = 0;
forEach(node.parameters, p => {
// A rest parameter cannot have a binding pattern or an initializer,
// so let's just ignore it.
if (p.dotDotDotToken) {
return;
}
if (isBindingPattern(p.name)) {
writeLine();
write("var ");
@@ -2892,6 +2890,12 @@ var __param = this.__param || function(index, decorator) { return function (targ
if (languageVersion < ScriptTarget.ES6 && hasRestParameters(node)) {
let restIndex = node.parameters.length - 1;
let restParam = node.parameters[restIndex];
// A rest parameter cannot have a binding pattern, so let's just ignore it if it does.
if (isBindingPattern(restParam.name)) {
return;
}
let tempName = createTempVariable(TempFlags._i).text;
writeLine();
emitLeadingComments(restParam);
@@ -4207,6 +4211,10 @@ var __param = this.__param || function(index, decorator) { return function (targ
return isInstantiatedModule(node, compilerOptions.preserveConstEnums || compilerOptions.separateCompilation);
}
function isModuleMergedWithES6Class(node: ModuleDeclaration) {
return languageVersion === ScriptTarget.ES6 && !!(resolver.getNodeCheckFlags(node) & NodeCheckFlags.LexicalModuleMergesWithClass);
}
function emitModuleDeclaration(node: ModuleDeclaration) {
// Emit only if this module is non-ambient.
let shouldEmit = shouldEmitModuleDeclaration(node);
@@ -4215,15 +4223,19 @@ var __param = this.__param || function(index, decorator) { return function (targ
return emitOnlyPinnedOrTripleSlashComments(node);
}
emitStart(node);
if (isES6ExportedDeclaration(node)) {
write("export ");
if (!isModuleMergedWithES6Class(node)) {
emitStart(node);
if (isES6ExportedDeclaration(node)) {
write("export ");
}
write("var ");
emit(node.name);
write(";");
emitEnd(node);
writeLine();
}
write("var ");
emit(node.name);
write(";");
emitEnd(node);
writeLine();
emitStart(node);
write("(function (");
emitStart(node.name);
+745 -750
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -54,6 +54,7 @@ module ts {
}
text = "";
}
return text !== undefined ? createSourceFile(fileName, text, languageVersion, setParentNodes) : undefined;
}
+41 -25
View File
@@ -25,6 +25,8 @@ module ts {
reScanTemplateToken(): SyntaxKind;
scan(): SyntaxKind;
setText(text: string): void;
setOnError(onError: ErrorCallback): void;
setScriptTarget(scriptTarget: ScriptTarget): void;
setTextPos(textPos: number): void;
// Invokes the provided callback then unconditionally restores the scanner to the state it
// was in immediately prior to invoking the callback. The result of invoking the callback
@@ -599,6 +601,7 @@ module ts {
export function createScanner(languageVersion: ScriptTarget, skipTrivia: boolean, text?: string, onError?: ErrorCallback): Scanner {
let pos: number; // Current position (end position of text of current token)
let len: number; // Length of text
let startPos: number; // Start position of whitespace before current token
let tokenPos: number; // Start position of text of current token
let token: SyntaxKind;
@@ -607,6 +610,32 @@ module ts {
let hasExtendedUnicodeEscape: boolean;
let tokenIsUnterminated: boolean;
setText(text);
return {
getStartPos: () => startPos,
getTextPos: () => pos,
getToken: () => token,
getTokenPos: () => tokenPos,
getTokenText: () => text.substring(tokenPos, pos),
getTokenValue: () => tokenValue,
hasExtendedUnicodeEscape: () => hasExtendedUnicodeEscape,
hasPrecedingLineBreak: () => precedingLineBreak,
isIdentifier: () => token === SyntaxKind.Identifier || token > SyntaxKind.LastReservedWord,
isReservedWord: () => token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord,
isUnterminated: () => tokenIsUnterminated,
reScanGreaterToken,
reScanSlashToken,
reScanTemplateToken,
scan,
setText,
setScriptTarget,
setOnError,
setTextPos,
tryScan,
lookAhead,
};
function error(message: DiagnosticMessage, length?: number): void {
if (onError) {
onError(message, length || 0);
@@ -1450,37 +1479,24 @@ module ts {
setTextPos(0);
}
function setOnError(errorCallback: ErrorCallback) {
onError = errorCallback;
}
function setScriptTarget(scriptTarget: ScriptTarget) {
languageVersion = scriptTarget;
}
function setTextPos(textPos: number) {
pos = textPos;
startPos = textPos;
tokenPos = textPos;
token = SyntaxKind.Unknown;
precedingLineBreak = false;
tokenValue = undefined;
hasExtendedUnicodeEscape = false;
tokenIsUnterminated = false;
}
setText(text);
return {
getStartPos: () => startPos,
getTextPos: () => pos,
getToken: () => token,
getTokenPos: () => tokenPos,
getTokenText: () => text.substring(tokenPos, pos),
getTokenValue: () => tokenValue,
hasExtendedUnicodeEscape: () => hasExtendedUnicodeEscape,
hasPrecedingLineBreak: () => precedingLineBreak,
isIdentifier: () => token === SyntaxKind.Identifier || token > SyntaxKind.LastReservedWord,
isReservedWord: () => token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord,
isUnterminated: () => tokenIsUnterminated,
reScanGreaterToken,
reScanSlashToken,
reScanTemplateToken,
scan,
setText,
setTextPos,
tryScan,
lookAhead,
};
}
}
+1
View File
@@ -1405,6 +1405,7 @@ module ts {
BlockScopedBindingInLoop = 0x00000100,
EmitDecorate = 0x00000200, // Emit __decorate
EmitParam = 0x00000400, // Emit __param helper for decorators
LexicalModuleMergesWithClass = 0x00000800, // Instantiated lexical module declaration is merged with a previous class declaration.
}
/* @internal */
+277 -217
View File
@@ -211,8 +211,10 @@ module ts {
isCatchClauseVariableDeclaration(declaration);
}
// Gets the nearest enclosing block scope container that has the provided node
// as a descendant, that is not the provided node.
export function getEnclosingBlockScopeContainer(node: Node): Node {
let current = node;
let current = node.parent;
while (current) {
if (isFunctionLike(current)) {
return current;
@@ -271,7 +273,6 @@ module ts {
};
}
/* @internal */
export function getSpanOfTokenAtPosition(sourceFile: SourceFile, pos: number): TextSpan {
let scanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/ true, sourceFile.text);
scanner.setTextPos(pos);
@@ -408,7 +409,6 @@ module ts {
export let fullTripleSlashReferencePathRegEx = /^(\/\/\/\s*<reference\s+path\s*=\s*)('|")(.+?)\2.*?\/>/
// Warning: This has the same semantics as the forEach family of functions,
// in that traversal terminates in the event that 'visitor' supplies a truthy value.
export function forEachReturnStatement<T>(body: Block, visitor: (stmt: ReturnStatement) => T): T {
@@ -439,7 +439,6 @@ module ts {
}
}
/* @internal */
export function isVariableLike(node: Node): boolean {
if (node) {
switch (node.kind) {
@@ -1151,218 +1150,7 @@ module ts {
}
return false;
}
export function textSpanEnd(span: TextSpan) {
return span.start + span.length
}
export function textSpanIsEmpty(span: TextSpan) {
return span.length === 0
}
export function textSpanContainsPosition(span: TextSpan, position: number) {
return position >= span.start && position < textSpanEnd(span);
}
// Returns true if 'span' contains 'other'.
export function textSpanContainsTextSpan(span: TextSpan, other: TextSpan) {
return other.start >= span.start && textSpanEnd(other) <= textSpanEnd(span);
}
export function textSpanOverlapsWith(span: TextSpan, other: TextSpan) {
let overlapStart = Math.max(span.start, other.start);
let overlapEnd = Math.min(textSpanEnd(span), textSpanEnd(other));
return overlapStart < overlapEnd;
}
export function textSpanOverlap(span1: TextSpan, span2: TextSpan) {
let overlapStart = Math.max(span1.start, span2.start);
let overlapEnd = Math.min(textSpanEnd(span1), textSpanEnd(span2));
if (overlapStart < overlapEnd) {
return createTextSpanFromBounds(overlapStart, overlapEnd);
}
return undefined;
}
export function textSpanIntersectsWithTextSpan(span: TextSpan, other: TextSpan) {
return other.start <= textSpanEnd(span) && textSpanEnd(other) >= span.start
}
export function textSpanIntersectsWith(span: TextSpan, start: number, length: number) {
let end = start + length;
return start <= textSpanEnd(span) && end >= span.start;
}
export function textSpanIntersectsWithPosition(span: TextSpan, position: number) {
return position <= textSpanEnd(span) && position >= span.start;
}
export function textSpanIntersection(span1: TextSpan, span2: TextSpan) {
let intersectStart = Math.max(span1.start, span2.start);
let intersectEnd = Math.min(textSpanEnd(span1), textSpanEnd(span2));
if (intersectStart <= intersectEnd) {
return createTextSpanFromBounds(intersectStart, intersectEnd);
}
return undefined;
}
export function createTextSpan(start: number, length: number): TextSpan {
if (start < 0) {
throw new Error("start < 0");
}
if (length < 0) {
throw new Error("length < 0");
}
return { start, length };
}
export function createTextSpanFromBounds(start: number, end: number) {
return createTextSpan(start, end - start);
}
export function textChangeRangeNewSpan(range: TextChangeRange) {
return createTextSpan(range.span.start, range.newLength);
}
export function textChangeRangeIsUnchanged(range: TextChangeRange) {
return textSpanIsEmpty(range.span) && range.newLength === 0;
}
export function createTextChangeRange(span: TextSpan, newLength: number): TextChangeRange {
if (newLength < 0) {
throw new Error("newLength < 0");
}
return { span, newLength };
}
export let unchangedTextChangeRange = createTextChangeRange(createTextSpan(0, 0), 0);
/**
* Called to merge all the changes that occurred across several versions of a script snapshot
* into a single change. i.e. if a user keeps making successive edits to a script we will
* have a text change from V1 to V2, V2 to V3, ..., Vn.
*
* This function will then merge those changes into a single change range valid between V1 and
* Vn.
*/
export function collapseTextChangeRangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange {
if (changes.length === 0) {
return unchangedTextChangeRange;
}
if (changes.length === 1) {
return changes[0];
}
// We change from talking about { { oldStart, oldLength }, newLength } to { oldStart, oldEnd, newEnd }
// as it makes things much easier to reason about.
let change0 = changes[0];
let oldStartN = change0.span.start;
let oldEndN = textSpanEnd(change0.span);
let newEndN = oldStartN + change0.newLength;
for (let i = 1; i < changes.length; i++) {
let nextChange = changes[i];
// Consider the following case:
// i.e. two edits. The first represents the text change range { { 10, 50 }, 30 }. i.e. The span starting
// at 10, with length 50 is reduced to length 30. The second represents the text change range { { 30, 30 }, 40 }.
// i.e. the span starting at 30 with length 30 is increased to length 40.
//
// 0 10 20 30 40 50 60 70 80 90 100
// -------------------------------------------------------------------------------------------------------
// | /
// | /----
// T1 | /----
// | /----
// | /----
// -------------------------------------------------------------------------------------------------------
// | \
// | \
// T2 | \
// | \
// | \
// -------------------------------------------------------------------------------------------------------
//
// Merging these turns out to not be too difficult. First, determining the new start of the change is trivial
// it's just the min of the old and new starts. i.e.:
//
// 0 10 20 30 40 50 60 70 80 90 100
// ------------------------------------------------------------*------------------------------------------
// | /
// | /----
// T1 | /----
// | /----
// | /----
// ----------------------------------------$-------------------$------------------------------------------
// . | \
// . | \
// T2 . | \
// . | \
// . | \
// ----------------------------------------------------------------------*--------------------------------
//
// (Note the dots represent the newly inferrred start.
// Determining the new and old end is also pretty simple. Basically it boils down to paying attention to the
// absolute positions at the asterixes, and the relative change between the dollar signs. Basically, we see
// which if the two $'s precedes the other, and we move that one forward until they line up. in this case that
// means:
//
// 0 10 20 30 40 50 60 70 80 90 100
// --------------------------------------------------------------------------------*----------------------
// | /
// | /----
// T1 | /----
// | /----
// | /----
// ------------------------------------------------------------$------------------------------------------
// . | \
// . | \
// T2 . | \
// . | \
// . | \
// ----------------------------------------------------------------------*--------------------------------
//
// In other words (in this case), we're recognizing that the second edit happened after where the first edit
// ended with a delta of 20 characters (60 - 40). Thus, if we go back in time to where the first edit started
// that's the same as if we started at char 80 instead of 60.
//
// As it so happens, the same logic applies if the second edit precedes the first edit. In that case rahter
// than pusing the first edit forward to match the second, we'll push the second edit forward to match the
// first.
//
// In this case that means we have { oldStart: 10, oldEnd: 80, newEnd: 70 } or, in TextChangeRange
// semantics: { { start: 10, length: 70 }, newLength: 60 }
//
// The math then works out as follows.
// If we have { oldStart1, oldEnd1, newEnd1 } and { oldStart2, oldEnd2, newEnd2 } then we can compute the
// final result like so:
//
// {
// oldStart3: Min(oldStart1, oldStart2),
// oldEnd3 : Max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)),
// newEnd3 : Max(newEnd2, newEnd2 + (newEnd1 - oldEnd2))
// }
let oldStart1 = oldStartN;
let oldEnd1 = oldEndN;
let newEnd1 = newEndN;
let oldStart2 = nextChange.span.start;
let oldEnd2 = textSpanEnd(nextChange.span);
let newEnd2 = oldStart2 + nextChange.newLength;
oldStartN = Math.min(oldStart1, oldStart2);
oldEndN = Math.max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1));
newEndN = Math.max(newEnd2, newEnd2 + (newEnd1 - oldEnd2));
}
return createTextChangeRange(createTextSpanFromBounds(oldStartN, oldEndN), /*newLength:*/ newEndN - oldStartN);
}
export function nodeStartsNewLexicalEnvironment(n: Node): boolean {
return isFunctionLike(n) || n.kind === SyntaxKind.ModuleDeclaration || n.kind === SyntaxKind.SourceFile;
}
@@ -1379,7 +1167,13 @@ module ts {
return node;
}
/* @internal */
export function createSynthesizedNodeArray(): NodeArray<any> {
var array = <NodeArray<any>>[];
array.pos = -1;
array.end = -1;
return array;
}
export function createDiagnosticCollection(): DiagnosticCollection {
let nonFileDiagnostics: Diagnostic[] = [];
let fileDiagnostics: Map<Diagnostic[]> = {};
@@ -1827,6 +1621,55 @@ module ts {
}
}
export function modifierToFlag(token: SyntaxKind): NodeFlags {
switch (token) {
case SyntaxKind.StaticKeyword: return NodeFlags.Static;
case SyntaxKind.PublicKeyword: return NodeFlags.Public;
case SyntaxKind.ProtectedKeyword: return NodeFlags.Protected;
case SyntaxKind.PrivateKeyword: return NodeFlags.Private;
case SyntaxKind.ExportKeyword: return NodeFlags.Export;
case SyntaxKind.DeclareKeyword: return NodeFlags.Ambient;
case SyntaxKind.ConstKeyword: return NodeFlags.Const;
case SyntaxKind.DefaultKeyword: return NodeFlags.Default;
}
return 0;
}
export function isLeftHandSideExpression(expr: Expression): boolean {
if (expr) {
switch (expr.kind) {
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ElementAccessExpression:
case SyntaxKind.NewExpression:
case SyntaxKind.CallExpression:
case SyntaxKind.TaggedTemplateExpression:
case SyntaxKind.ArrayLiteralExpression:
case SyntaxKind.ParenthesizedExpression:
case SyntaxKind.ObjectLiteralExpression:
case SyntaxKind.ClassExpression:
case SyntaxKind.FunctionExpression:
case SyntaxKind.Identifier:
case SyntaxKind.RegularExpressionLiteral:
case SyntaxKind.NumericLiteral:
case SyntaxKind.StringLiteral:
case SyntaxKind.NoSubstitutionTemplateLiteral:
case SyntaxKind.TemplateExpression:
case SyntaxKind.FalseKeyword:
case SyntaxKind.NullKeyword:
case SyntaxKind.ThisKeyword:
case SyntaxKind.TrueKeyword:
case SyntaxKind.SuperKeyword:
return true;
}
}
return false;
}
export function isAssignmentOperator(token: SyntaxKind): boolean {
return token >= SyntaxKind.FirstAssignment && token <= SyntaxKind.LastAssignment;
}
// Returns false if this heritage clause element's expression contains something unsupported
// (i.e. not a name or dotted name).
export function isSupportedHeritageClauseElement(node: HeritageClauseElement): boolean {
@@ -1854,3 +1697,220 @@ module ts {
return symbol && symbol.valueDeclaration && (symbol.valueDeclaration.flags & NodeFlags.Default) ? symbol.valueDeclaration.localSymbol : undefined;
}
}
module ts {
export function getDefaultLibFileName(options: CompilerOptions): string {
return options.target === ScriptTarget.ES6 ? "lib.es6.d.ts" : "lib.d.ts";
}
export function textSpanEnd(span: TextSpan) {
return span.start + span.length
}
export function textSpanIsEmpty(span: TextSpan) {
return span.length === 0
}
export function textSpanContainsPosition(span: TextSpan, position: number) {
return position >= span.start && position < textSpanEnd(span);
}
// Returns true if 'span' contains 'other'.
export function textSpanContainsTextSpan(span: TextSpan, other: TextSpan) {
return other.start >= span.start && textSpanEnd(other) <= textSpanEnd(span);
}
export function textSpanOverlapsWith(span: TextSpan, other: TextSpan) {
let overlapStart = Math.max(span.start, other.start);
let overlapEnd = Math.min(textSpanEnd(span), textSpanEnd(other));
return overlapStart < overlapEnd;
}
export function textSpanOverlap(span1: TextSpan, span2: TextSpan) {
let overlapStart = Math.max(span1.start, span2.start);
let overlapEnd = Math.min(textSpanEnd(span1), textSpanEnd(span2));
if (overlapStart < overlapEnd) {
return createTextSpanFromBounds(overlapStart, overlapEnd);
}
return undefined;
}
export function textSpanIntersectsWithTextSpan(span: TextSpan, other: TextSpan) {
return other.start <= textSpanEnd(span) && textSpanEnd(other) >= span.start
}
export function textSpanIntersectsWith(span: TextSpan, start: number, length: number) {
let end = start + length;
return start <= textSpanEnd(span) && end >= span.start;
}
export function textSpanIntersectsWithPosition(span: TextSpan, position: number) {
return position <= textSpanEnd(span) && position >= span.start;
}
export function textSpanIntersection(span1: TextSpan, span2: TextSpan) {
let intersectStart = Math.max(span1.start, span2.start);
let intersectEnd = Math.min(textSpanEnd(span1), textSpanEnd(span2));
if (intersectStart <= intersectEnd) {
return createTextSpanFromBounds(intersectStart, intersectEnd);
}
return undefined;
}
export function createTextSpan(start: number, length: number): TextSpan {
if (start < 0) {
throw new Error("start < 0");
}
if (length < 0) {
throw new Error("length < 0");
}
return { start, length };
}
export function createTextSpanFromBounds(start: number, end: number) {
return createTextSpan(start, end - start);
}
export function textChangeRangeNewSpan(range: TextChangeRange) {
return createTextSpan(range.span.start, range.newLength);
}
export function textChangeRangeIsUnchanged(range: TextChangeRange) {
return textSpanIsEmpty(range.span) && range.newLength === 0;
}
export function createTextChangeRange(span: TextSpan, newLength: number): TextChangeRange {
if (newLength < 0) {
throw new Error("newLength < 0");
}
return { span, newLength };
}
export let unchangedTextChangeRange = createTextChangeRange(createTextSpan(0, 0), 0);
/**
* Called to merge all the changes that occurred across several versions of a script snapshot
* into a single change. i.e. if a user keeps making successive edits to a script we will
* have a text change from V1 to V2, V2 to V3, ..., Vn.
*
* This function will then merge those changes into a single change range valid between V1 and
* Vn.
*/
export function collapseTextChangeRangesAcrossMultipleVersions(changes: TextChangeRange[]): TextChangeRange {
if (changes.length === 0) {
return unchangedTextChangeRange;
}
if (changes.length === 1) {
return changes[0];
}
// We change from talking about { { oldStart, oldLength }, newLength } to { oldStart, oldEnd, newEnd }
// as it makes things much easier to reason about.
let change0 = changes[0];
let oldStartN = change0.span.start;
let oldEndN = textSpanEnd(change0.span);
let newEndN = oldStartN + change0.newLength;
for (let i = 1; i < changes.length; i++) {
let nextChange = changes[i];
// Consider the following case:
// i.e. two edits. The first represents the text change range { { 10, 50 }, 30 }. i.e. The span starting
// at 10, with length 50 is reduced to length 30. The second represents the text change range { { 30, 30 }, 40 }.
// i.e. the span starting at 30 with length 30 is increased to length 40.
//
// 0 10 20 30 40 50 60 70 80 90 100
// -------------------------------------------------------------------------------------------------------
// | /
// | /----
// T1 | /----
// | /----
// | /----
// -------------------------------------------------------------------------------------------------------
// | \
// | \
// T2 | \
// | \
// | \
// -------------------------------------------------------------------------------------------------------
//
// Merging these turns out to not be too difficult. First, determining the new start of the change is trivial
// it's just the min of the old and new starts. i.e.:
//
// 0 10 20 30 40 50 60 70 80 90 100
// ------------------------------------------------------------*------------------------------------------
// | /
// | /----
// T1 | /----
// | /----
// | /----
// ----------------------------------------$-------------------$------------------------------------------
// . | \
// . | \
// T2 . | \
// . | \
// . | \
// ----------------------------------------------------------------------*--------------------------------
//
// (Note the dots represent the newly inferrred start.
// Determining the new and old end is also pretty simple. Basically it boils down to paying attention to the
// absolute positions at the asterixes, and the relative change between the dollar signs. Basically, we see
// which if the two $'s precedes the other, and we move that one forward until they line up. in this case that
// means:
//
// 0 10 20 30 40 50 60 70 80 90 100
// --------------------------------------------------------------------------------*----------------------
// | /
// | /----
// T1 | /----
// | /----
// | /----
// ------------------------------------------------------------$------------------------------------------
// . | \
// . | \
// T2 . | \
// . | \
// . | \
// ----------------------------------------------------------------------*--------------------------------
//
// In other words (in this case), we're recognizing that the second edit happened after where the first edit
// ended with a delta of 20 characters (60 - 40). Thus, if we go back in time to where the first edit started
// that's the same as if we started at char 80 instead of 60.
//
// As it so happens, the same logic applies if the second edit precedes the first edit. In that case rahter
// than pusing the first edit forward to match the second, we'll push the second edit forward to match the
// first.
//
// In this case that means we have { oldStart: 10, oldEnd: 80, newEnd: 70 } or, in TextChangeRange
// semantics: { { start: 10, length: 70 }, newLength: 60 }
//
// The math then works out as follows.
// If we have { oldStart1, oldEnd1, newEnd1 } and { oldStart2, oldEnd2, newEnd2 } then we can compute the
// final result like so:
//
// {
// oldStart3: Min(oldStart1, oldStart2),
// oldEnd3 : Max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1)),
// newEnd3 : Max(newEnd2, newEnd2 + (newEnd1 - oldEnd2))
// }
let oldStart1 = oldStartN;
let oldEnd1 = oldEndN;
let newEnd1 = newEndN;
let oldStart2 = nextChange.span.start;
let oldEnd2 = textSpanEnd(nextChange.span);
let newEnd2 = oldStart2 + nextChange.newLength;
oldStartN = Math.min(oldStart1, oldStart2);
oldEndN = Math.max(oldEnd1, oldEnd1 + (oldEnd2 - newEnd1));
newEndN = Math.max(newEnd2, newEnd2 + (newEnd1 - oldEnd2));
}
return createTextChangeRange(createTextSpanFromBounds(oldStartN, oldEndN), /*newLength:*/ newEndN - oldStartN);
}
}
+48 -18
View File
@@ -253,6 +253,10 @@ class CompilerBaselineRunner extends RunnerBase {
});
it('Correct type baselines for ' + fileName, () => {
if (fileName.indexOf("APISample") >= 0) {
return;
}
// NEWTODO: Type baselines
if (result.errors.length === 0) {
// The full walker simulates the types that you would get from doing a full
@@ -270,29 +274,53 @@ class CompilerBaselineRunner extends RunnerBase {
// These types are equivalent, but depend on what order the compiler observed
// certain parts of the program.
var fullWalker = new TypeWriterWalker(program, /*fullTypeCheck:*/ true);
var pullWalker = new TypeWriterWalker(program, /*fullTypeCheck:*/ false);
let allFiles = toBeCompiled.concat(otherFiles).filter(file => !!program.getSourceFile(file.unitName));
var fullTypes = generateTypes(fullWalker);
var pullTypes = generateTypes(pullWalker);
let fullWalker = new TypeWriterWalker(program, /*fullTypeCheck:*/ true);
let pullWalker = new TypeWriterWalker(program, /*fullTypeCheck:*/ false);
if (fullTypes !== pullTypes) {
Harness.Baseline.runBaseline('Correct full expression types for ' + fileName, justName.replace(/\.ts/, '.types'), () => fullTypes);
Harness.Baseline.runBaseline('Correct pull expression types for ' + fileName, justName.replace(/\.ts/, '.types.pull'), () => pullTypes);
}
else {
Harness.Baseline.runBaseline('Correct expression types for ' + fileName, justName.replace(/\.ts/, '.types'), () => fullTypes);
let fullResults: ts.Map<TypeWriterResult[]> = {};
let pullResults: ts.Map<TypeWriterResult[]> = {};
for (let sourceFile of allFiles) {
fullResults[sourceFile.unitName] = fullWalker.getTypeAndSymbols(sourceFile.unitName);
pullResults[sourceFile.unitName] = fullWalker.getTypeAndSymbols(sourceFile.unitName);
}
function generateTypes(walker: TypeWriterWalker): string {
var allFiles = toBeCompiled.concat(otherFiles).filter(file => !!program.getSourceFile(file.unitName));
var typeLines: string[] = [];
var typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {};
// Produce baselines. The first gives the types for all expressions.
// The second gives symbols for all identifiers.
checkBaseLines(/*isSymbolBaseLine:*/ false);
checkBaseLines(/*isSymbolBaseLine:*/ true);
function checkBaseLines(isSymbolBaseLine: boolean) {
let fullBaseLine = generateBaseLine(fullResults, isSymbolBaseLine);
let pullBaseLine = generateBaseLine(pullResults, isSymbolBaseLine);
let fullExtension = isSymbolBaseLine ? '.symbols' : '.types';
let pullExtension = isSymbolBaseLine ? '.symbols.pull' : '.types.pull';
if (fullBaseLine !== pullBaseLine) {
Harness.Baseline.runBaseline('Correct full information for ' + fileName, justName.replace(/\.ts/, fullExtension), () => fullBaseLine);
Harness.Baseline.runBaseline('Correct pull information for ' + fileName, justName.replace(/\.ts/, pullExtension), () => pullBaseLine);
}
else {
Harness.Baseline.runBaseline('Correct information for ' + fileName, justName.replace(/\.ts/, fullExtension), () => fullBaseLine);
}
}
function generateBaseLine(typeWriterResults: ts.Map<TypeWriterResult[]>, isSymbolBaseline: boolean): string {
let typeLines: string[] = [];
let typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {};
allFiles.forEach(file => {
var codeLines = file.content.split('\n');
walker.getTypes(file.unitName).forEach(result => {
var formattedLine = result.sourceText.replace(/\r?\n/g, "") + " : " + result.type;
typeWriterResults[file.unitName].forEach(result => {
if (isSymbolBaseline && !result.symbol) {
return;
}
var typeOrSymbolString = isSymbolBaseline ? result.symbol : result.type;
var formattedLine = result.sourceText.replace(/\r?\n/g, "") + " : " + typeOrSymbolString;
if (!typeMap[file.unitName]) {
typeMap[file.unitName] = {};
}
@@ -316,11 +344,13 @@ class CompilerBaselineRunner extends RunnerBase {
typeLines.push('>' + ty + '\r\n');
});
if (i + 1 < codeLines.length && (codeLines[i + 1].match(/^\s*[{|}]\s*$/) || codeLines[i + 1].trim() === '')) {
} else {
}
else {
typeLines.push('\r\n');
}
}
} else {
}
else {
typeLines.push('No type information for this code.');
}
}
+6 -5
View File
@@ -3,6 +3,7 @@ interface TypeWriterResult {
syntaxKind: number;
sourceText: string;
type: string;
symbol: string;
}
class TypeWriterWalker {
@@ -19,7 +20,7 @@ class TypeWriterWalker {
: program.getTypeChecker();
}
public getTypes(fileName: string): TypeWriterResult[] {
public getTypeAndSymbols(fileName: string): TypeWriterResult[] {
var sourceFile = this.program.getSourceFile(fileName);
this.currentSourceFile = sourceFile;
this.results = [];
@@ -45,8 +46,9 @@ class TypeWriterWalker {
var symbol = this.checker.getSymbolAtLocation(node);
var typeString = this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation);
var symbolString: string;
if (symbol) {
var symbolString = "Symbol(" + this.checker.symbolToString(symbol, node.parent);
symbolString = "Symbol(" + this.checker.symbolToString(symbol, node.parent);
if (symbol.declarations) {
for (let declaration of symbol.declarations) {
symbolString += ", ";
@@ -56,15 +58,14 @@ class TypeWriterWalker {
}
}
symbolString += ")";
typeString += ", " + symbolString;
}
this.results.push({
line: lineAndCharacter.line,
syntaxKind: node.kind,
sourceText: sourceText,
type: typeString
type: typeString,
symbol: symbolString
});
}
}
+110 -4
View File
@@ -21,13 +21,16 @@ interface TextStreamBase {
* The column number of the current character position in an input stream.
*/
Column: number;
/**
* The current line number in an input stream.
*/
Line: number;
/**
* Closes a text stream.
* It is not necessary to close standard streams; they close automatically when the process ends. If you close a standard stream, be aware that any other pointers to that standard stream become invalid.
* It is not necessary to close standard streams; they close automatically when the process ends. If
* you close a standard stream, be aware that any other pointers to that standard stream become invalid.
*/
Close(): void;
}
@@ -37,10 +40,12 @@ interface TextStreamWriter extends TextStreamBase {
* Sends a string to an output stream.
*/
Write(s: string): void;
/**
* Sends a specified number of blank lines (newline characters) to an output stream.
*/
WriteBlankLines(intLines: number): void;
/**
* Sends a string followed by a newline character to an output stream.
*/
@@ -49,37 +54,43 @@ interface TextStreamWriter extends TextStreamBase {
interface TextStreamReader extends TextStreamBase {
/**
* Returns a specified number of characters from an input stream, beginning at the current pointer position.
* Returns a specified number of characters from an input stream, starting at the current pointer position.
* Does not return until the ENTER key is pressed.
* Can only be used on a stream in reading mode; causes an error in writing or appending mode.
*/
Read(characters: number): string;
/**
* Returns all characters from an input stream.
* Can only be used on a stream in reading mode; causes an error in writing or appending mode.
*/
ReadAll(): string;
/**
* Returns an entire line from an input stream.
* Although this method extracts the newline character, it does not add it to the returned string.
* Can only be used on a stream in reading mode; causes an error in writing or appending mode.
*/
ReadLine(): string;
/**
* Skips a specified number of characters when reading from an input text stream.
* Can only be used on a stream in reading mode; causes an error in writing or appending mode.
* @param characters Positive number of characters to skip forward. (Backward skipping is not supported.)
*/
Skip(characters: number): void;
/**
* Skips the next line when reading from an input text stream.
* Can only be used on a stream in reading mode, not writing or appending mode.
*/
SkipLine(): void;
/**
* Indicates whether the stream pointer position is at the end of a line.
*/
AtEndOfLine: boolean;
/**
* Indicates whether the stream pointer position is at the end of a stream.
*/
@@ -88,85 +99,180 @@ interface TextStreamReader extends TextStreamBase {
declare var WScript: {
/**
* Outputs text to either a message box (under WScript.exe) or the command console window followed by a newline (under CScript.ext).
* Outputs text to either a message box (under WScript.exe) or the command console window followed by
* a newline (under CScript.exe).
*/
Echo(s: any): void;
/**
* Exposes the write-only error output stream for the current script.
* Can be accessed only while using CScript.exe.
*/
StdErr: TextStreamWriter;
/**
* Exposes the write-only output stream for the current script.
* Can be accessed only while using CScript.exe.
*/
StdOut: TextStreamWriter;
Arguments: { length: number; Item(n: number): string; };
/**
* The full path of the currently running script.
*/
ScriptFullName: string;
/**
* Forces the script to stop immediately, with an optional exit code.
*/
Quit(exitCode?: number): number;
/**
* The Windows Script Host build version number.
*/
BuildVersion: number;
/**
* Fully qualified path of the host executable.
*/
FullName: string;
/**
* Gets/sets the script mode - interactive(true) or batch(false).
*/
Interactive: boolean;
/**
* The name of the host executable (WScript.exe or CScript.exe).
*/
Name: string;
/**
* Path of the directory containing the host executable.
*/
Path: string;
/**
* The filename of the currently running script.
*/
ScriptName: string;
/**
* Exposes the read-only input stream for the current script.
* Can be accessed only while using CScript.exe.
*/
StdIn: TextStreamReader;
/**
* Windows Script Host version
*/
Version: string;
/**
* Connects a COM object's event sources to functions named with a given prefix, in the form prefix_event.
*/
ConnectObject(objEventSource: any, strPrefix: string): void;
/**
* Creates a COM object.
* @param strProgiID
* @param strPrefix Function names in the form prefix_event will be bound to this object's COM events.
*/
CreateObject(strProgID: string, strPrefix?: string): any;
/**
* Disconnects a COM object from its event sources.
*/
DisconnectObject(obj: any): void;
/**
* Retrieves an existing object with the specified ProgID from memory, or creates a new one from a file.
* @param strPathname Fully qualified path to the file containing the object persisted to disk. For objects in memory, pass a zero-length string.
* @param strPathname Fully qualified path to the file containing the object persisted to disk.
* For objects in memory, pass a zero-length string.
* @param strProgID
* @param strPrefix Function names in the form prefix_event will be bound to this object's COM events.
*/
GetObject(strPathname: string, strProgID?: string, strPrefix?: string): any;
/**
* Suspends script execution for a specified length of time, then continues execution.
* @param intTime Interval (in milliseconds) to suspend script execution.
*/
Sleep(intTime: number): void;
};
/**
* Allows enumerating over a COM collection, which may not have indexed item access.
*/
interface Enumerator<T> {
/**
* Returns true if the current item is the last one in the collection, or the collection is empty,
* or the current item is undefined.
*/
atEnd(): boolean;
/**
* Returns the current item in the collection
*/
item(): T;
/**
* Resets the current item in the collection to the first item. If there are no items in the collection,
* the current item is set to undefined.
*/
moveFirst(): void;
/**
* Moves the current item to the next item in the collection. If the enumerator is at the end of
* the collection or the collection is empty, the current item is set to undefined.
*/
moveNext(): void;
}
interface EnumeratorConstructor {
new <T>(collection: any): Enumerator<T>;
new (collection: any): Enumerator<any>;
}
declare var Enumerator: EnumeratorConstructor;
/**
* Enables reading from a COM safe array, which might have an alternate lower bound, or multiple dimensions.
*/
interface VBArray<T> {
/**
* Returns the number of dimensions (1-based).
*/
dimensions(): number;
/**
* Takes an index for each dimension in the array, and returns the item at the corresponding location.
*/
getItem(dimension1Index: number, ...dimensionNIndexes: number[]): T;
/**
* Returns the smallest available index for a given dimension.
* @param dimension 1-based dimension (defaults to 1)
*/
lbound(dimension?: number): number;
/**
* Returns the largest available index for a given dimension.
* @param dimension 1-based dimension (defaults to 1)
*/
ubound(dimension?: number): number;
/**
* Returns a Javascript array with all the elements in the VBArray. If there are multiple dimensions,
* each successive dimension is appended to the end of the array.
* Example: [[1,2,3],[4,5,6]] becomes [1,2,3,4,5,6]
*/
toArray(): T[];
}
interface VBArrayConstructor {
new <T>(safeArray: any): VBArray<T>;
new (safeArray: any): VBArray<any>;
}
declare var VBArray: VBArrayConstructor;