Merge branch 'master' into multi_map_add

This commit is contained in:
Andy Hanson
2016-09-02 06:10:04 -07:00
236 changed files with 3604 additions and 2297 deletions
+199 -133
View File
@@ -106,7 +106,7 @@ namespace ts {
isOptionalParameter
};
const tupleTypes = createMap<TupleType>();
const tupleTypes: GenericType[] = [];
const unionTypes = createMap<UnionType>();
const intersectionTypes = createMap<IntersectionType>();
const stringLiteralTypes = createMap<LiteralType>();
@@ -1023,8 +1023,8 @@ namespace ts {
}
}
function getDeclarationOfAliasSymbol(symbol: Symbol): Declaration {
return findMap(symbol.declarations, d => isAliasSymbolDeclaration(d) ? d : undefined);
function getDeclarationOfAliasSymbol(symbol: Symbol): Declaration | undefined {
return forEach(symbol.declarations, d => isAliasSymbolDeclaration(d) ? d : undefined);
}
function getTargetOfImportEqualsDeclaration(node: ImportEqualsDeclaration): Symbol {
@@ -1126,13 +1126,13 @@ namespace ts {
else {
symbolFromVariable = getPropertyOfVariable(targetSymbol, name.text);
}
// If the export member we're looking for is default, and there is no real default but allowSyntheticDefaultImports is on, return the entire module as the default
if (!symbolFromVariable && allowSyntheticDefaultImports && name.text === "default") {
symbolFromVariable = resolveExternalModuleSymbol(moduleSymbol) || resolveSymbol(moduleSymbol);
}
// if symbolFromVariable is export - get its final target
symbolFromVariable = resolveSymbol(symbolFromVariable);
const symbolFromModule = getExportOfModule(targetSymbol, name.text);
let symbolFromModule = getExportOfModule(targetSymbol, name.text);
// If the export member we're looking for is default, and there is no real default but allowSyntheticDefaultImports is on, return the entire module as the default
if (!symbolFromModule && allowSyntheticDefaultImports && name.text === "default") {
symbolFromModule = resolveExternalModuleSymbol(moduleSymbol) || resolveSymbol(moduleSymbol);
}
const symbol = symbolFromModule && symbolFromVariable ?
combineValueAndTypeSymbols(symbolFromVariable, symbolFromModule) :
symbolFromModule || symbolFromVariable;
@@ -1191,6 +1191,7 @@ namespace ts {
if (!links.target) {
links.target = resolvingSymbol;
const node = getDeclarationOfAliasSymbol(symbol);
Debug.assert(!!node);
const target = getTargetOfAliasDeclaration(node);
if (links.target === resolvingSymbol) {
links.target = target || unknownSymbol;
@@ -1226,6 +1227,7 @@ namespace ts {
if (!links.referenced) {
links.referenced = true;
const node = getDeclarationOfAliasSymbol(symbol);
Debug.assert(!!node);
if (node.kind === SyntaxKind.ExportAssignment) {
// export default <symbol>
checkExpressionCached((<ExportAssignment>node).expression);
@@ -2145,9 +2147,6 @@ namespace ts {
// The specified symbol flags need to be reinterpreted as type flags
buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Type, SymbolFormatFlags.None, nextFlags);
}
else if (type.flags & TypeFlags.Tuple) {
writeTupleType(<TupleType>type);
}
else if (!(flags & TypeFormatFlags.InTypeAlias) && type.flags & (TypeFlags.Anonymous | TypeFlags.UnionOrIntersection) && type.aliasSymbol) {
const typeArguments = type.aliasTypeArguments;
writeSymbolTypeReference(type.aliasSymbol, typeArguments, 0, typeArguments ? typeArguments.length : 0, nextFlags);
@@ -2214,6 +2213,11 @@ namespace ts {
writePunctuation(writer, SyntaxKind.OpenBracketToken);
writePunctuation(writer, SyntaxKind.CloseBracketToken);
}
else if (type.target.flags & TypeFlags.Tuple) {
writePunctuation(writer, SyntaxKind.OpenBracketToken);
writeTypeList(type.typeArguments.slice(0, getTypeReferenceArity(type)), SyntaxKind.CommaToken);
writePunctuation(writer, SyntaxKind.CloseBracketToken);
}
else {
// Write the type reference in the format f<A>.g<B>.C<X, Y> where A and B are type arguments
// for outer type parameters, and f and g are the respective declaring containers of those
@@ -2242,12 +2246,6 @@ namespace ts {
}
}
function writeTupleType(type: TupleType) {
writePunctuation(writer, SyntaxKind.OpenBracketToken);
writeTypeList(type.elementTypes, SyntaxKind.CommaToken);
writePunctuation(writer, SyntaxKind.CloseBracketToken);
}
function writeUnionOrIntersectionType(type: UnionOrIntersectionType, flags: TypeFormatFlags) {
if (flags & TypeFormatFlags.InElementType) {
writePunctuation(writer, SyntaxKind.OpenParenToken);
@@ -2958,7 +2956,7 @@ namespace ts {
: elementType;
if (!type) {
if (isTupleType(parentType)) {
error(declaration, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(parentType), (<TupleType>parentType).elementTypes.length, pattern.elements.length);
error(declaration, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(parentType), getTypeReferenceArity(<TypeReference>parentType), pattern.elements.length);
}
else {
error(declaration, Diagnostics.Type_0_has_no_property_1, typeToString(parentType), propName);
@@ -3070,9 +3068,14 @@ namespace ts {
}
}
// Use contextual parameter type if one is available
const type = declaration.symbol.name === "this"
? getContextuallyTypedThisType(func)
: getContextuallyTypedParameterType(<ParameterDeclaration>declaration);
let type: Type;
if (declaration.symbol.name === "this") {
const thisParameter = getContextualThisParameter(func);
type = thisParameter ? getTypeOfSymbol(thisParameter) : undefined;
}
else {
type = getContextuallyTypedParameterType(<ParameterDeclaration>declaration);
}
if (type) {
return addOptionality(type, /*optional*/ declaration.questionToken && includeOptionality);
}
@@ -3150,12 +3153,12 @@ namespace ts {
}
// If the pattern has at least one element, and no rest element, then it should imply a tuple type.
const elementTypes = map(elements, e => e.kind === SyntaxKind.OmittedExpression ? anyType : getTypeFromBindingElement(e, includePatternInType, reportErrors));
let result = createTupleType(elementTypes);
if (includePatternInType) {
const result = createNewTupleType(elementTypes);
result = cloneTypeReference(result);
result.pattern = pattern;
return result;
}
return createTupleType(elementTypes);
return result;
}
// Return the type implied by a binding pattern. This is the type implied purely by the binding pattern itself
@@ -3343,7 +3346,13 @@ namespace ts {
// Otherwise, fall back to 'any'.
else {
if (compilerOptions.noImplicitAny) {
error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_type_annotation, symbolToString(symbol));
if (setter) {
error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, symbolToString(symbol));
}
else {
Debug.assert(!!getter, "there must existed getter as we are current checking either setter or getter in this function");
error(getter, Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, symbolToString(symbol));
}
}
type = anyType;
}
@@ -3564,18 +3573,21 @@ namespace ts {
}
function getBaseTypes(type: InterfaceType): ObjectType[] {
const isClass = type.symbol.flags & SymbolFlags.Class;
const isInterface = type.symbol.flags & SymbolFlags.Interface;
if (!type.resolvedBaseTypes) {
if (!isClass && !isInterface) {
if (type.flags & TypeFlags.Tuple) {
type.resolvedBaseTypes = [createArrayType(getUnionType(type.typeParameters))];
}
else if (type.symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
if (type.symbol.flags & SymbolFlags.Class) {
resolveBaseTypesOfClass(type);
}
if (type.symbol.flags & SymbolFlags.Interface) {
resolveBaseTypesOfInterface(type);
}
}
else {
Debug.fail("type must be class or interface");
}
if (isClass) {
resolveBaseTypesOfClass(type);
}
if (isInterface) {
resolveBaseTypesOfInterface(type);
}
}
return type.resolvedBaseTypes;
}
@@ -4001,20 +4013,25 @@ namespace ts {
return createTypeReference((<TypeReference>type).target,
concatenate((<TypeReference>type).typeArguments, [thisArgument || (<TypeReference>type).target.thisType]));
}
if (type.flags & TypeFlags.Tuple) {
return createTupleType((type as TupleType).elementTypes, thisArgument);
}
return type;
}
function resolveObjectTypeMembers(type: ObjectType, source: InterfaceTypeWithDeclaredMembers, typeParameters: TypeParameter[], typeArguments: Type[]) {
let mapper = identityMapper;
let members = source.symbol.members;
let callSignatures = source.declaredCallSignatures;
let constructSignatures = source.declaredConstructSignatures;
let stringIndexInfo = source.declaredStringIndexInfo;
let numberIndexInfo = source.declaredNumberIndexInfo;
if (!rangeEquals(typeParameters, typeArguments, 0, typeParameters.length)) {
let mapper: TypeMapper;
let members: SymbolTable;
let callSignatures: Signature[];
let constructSignatures: Signature[];
let stringIndexInfo: IndexInfo;
let numberIndexInfo: IndexInfo;
if (rangeEquals(typeParameters, typeArguments, 0, typeParameters.length)) {
mapper = identityMapper;
members = source.symbol ? source.symbol.members : createSymbolTable(source.declaredProperties);
callSignatures = source.declaredCallSignatures;
constructSignatures = source.declaredConstructSignatures;
stringIndexInfo = source.declaredStringIndexInfo;
numberIndexInfo = source.declaredNumberIndexInfo;
}
else {
mapper = createTypeMapper(typeParameters, typeArguments);
members = createInstantiatedSymbolTable(source.declaredProperties, mapper, /*mappingThisOnly*/ typeParameters.length === 1);
callSignatures = instantiateList(source.declaredCallSignatures, mapper, instantiateSignature);
@@ -4024,7 +4041,7 @@ namespace ts {
}
const baseTypes = getBaseTypes(source);
if (baseTypes.length) {
if (members === source.symbol.members) {
if (source.symbol && members === source.symbol.members) {
members = createSymbolTable(source.declaredProperties);
}
const thisArgument = lastOrUndefined(typeArguments);
@@ -4094,26 +4111,6 @@ namespace ts {
return result;
}
function createTupleTypeMemberSymbols(memberTypes: Type[]): SymbolTable {
const members = createMap<Symbol>();
for (let i = 0; i < memberTypes.length; i++) {
const symbol = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "" + i);
symbol.type = memberTypes[i];
members[i] = symbol;
}
return members;
}
function resolveTupleTypeMembers(type: TupleType) {
const arrayElementType = getUnionType(type.elementTypes);
// Make the tuple type itself the 'this' type by including an extra type argument
// (Unless it's provided in the case that the tuple is a type parameter constraint)
const arrayType = resolveStructuredTypeMembers(createTypeFromGenericGlobalType(globalArrayType, [arrayElementType, type.thisType || type]));
const members = createTupleTypeMemberSymbols(type.elementTypes);
addInheritedMembers(members, arrayType.properties);
setObjectTypeMembers(type, members, arrayType.callSignatures, arrayType.constructSignatures, arrayType.stringIndexInfo, arrayType.numberIndexInfo);
}
function findMatchingSignature(signatureList: Signature[], signature: Signature, partialMatch: boolean, ignoreThisTypes: boolean, ignoreReturnTypes: boolean): Signature {
for (const s of signatureList) {
if (compareSignaturesIdentical(s, signature, partialMatch, ignoreThisTypes, ignoreReturnTypes, compareTypesIdentical)) {
@@ -4292,9 +4289,6 @@ namespace ts {
else if (type.flags & TypeFlags.Anonymous) {
resolveAnonymousTypeMembers(<AnonymousType>type);
}
else if (type.flags & TypeFlags.Tuple) {
resolveTupleTypeMembers(<TupleType>type);
}
else if (type.flags & TypeFlags.Union) {
resolveUnionTypeMembers(<UnionType>type);
}
@@ -4694,6 +4688,9 @@ namespace ts {
if (isJSConstructSignature) {
minArgumentCount--;
}
if (!thisParameter && isObjectLiteralMethod(declaration)) {
thisParameter = getContextualThisParameter(declaration);
}
const classType = declaration.kind === SyntaxKind.Constructor ?
getDeclaredTypeOfClassOrInterface(getMergedSymbol((<ClassDeclaration>declaration.parent).symbol))
@@ -4992,6 +4989,17 @@ namespace ts {
return type;
}
function cloneTypeReference(source: TypeReference): TypeReference {
const type = <TypeReference>createObjectType(source.flags, source.symbol);
type.target = source.target;
type.typeArguments = source.typeArguments;
return type;
}
function getTypeReferenceArity(type: TypeReference): number {
return type.target.typeParameters ? type.target.typeParameters.length : 0;
}
// Get type from reference to class or interface
function getTypeFromClassOrInterfaceReference(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference, symbol: Symbol): Type {
const type = <InterfaceType>getDeclaredTypeOfSymbol(getMergedSymbol(symbol));
@@ -5234,17 +5242,47 @@ namespace ts {
return links.resolvedType;
}
function createTupleType(elementTypes: Type[], thisType?: Type) {
const id = getTypeListId(elementTypes) + "," + (thisType ? thisType.id : 0);
return tupleTypes[id] || (tupleTypes[id] = createNewTupleType(elementTypes, thisType));
// We represent tuple types as type references to synthesized generic interface types created by
// this function. The types are of the form:
//
// interface Tuple<T0, T1, T2, ...> extends Array<T0 | T1 | T2 | ...> { 0: T0, 1: T1, 2: T2, ... }
//
// Note that the generic type created by this function has no symbol associated with it. The same
// is true for each of the synthesized type parameters.
function createTupleTypeOfArity(arity: number): GenericType {
const typeParameters: TypeParameter[] = [];
const properties: Symbol[] = [];
for (let i = 0; i < arity; i++) {
const typeParameter = <TypeParameter>createType(TypeFlags.TypeParameter);
typeParameters.push(typeParameter);
const property = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "" + i);
property.type = typeParameter;
properties.push(property);
}
const type = <GenericType & InterfaceTypeWithDeclaredMembers>createObjectType(TypeFlags.Tuple | TypeFlags.Reference);
type.typeParameters = typeParameters;
type.outerTypeParameters = undefined;
type.localTypeParameters = typeParameters;
type.instantiations = createMap<TypeReference>();
type.instantiations[getTypeListId(type.typeParameters)] = <GenericType>type;
type.target = <GenericType>type;
type.typeArguments = type.typeParameters;
type.thisType = <TypeParameter>createType(TypeFlags.TypeParameter | TypeFlags.ThisType);
type.thisType.constraint = type;
type.declaredProperties = properties;
type.declaredCallSignatures = emptyArray;
type.declaredConstructSignatures = emptyArray;
type.declaredStringIndexInfo = undefined;
type.declaredNumberIndexInfo = undefined;
return type;
}
function createNewTupleType(elementTypes: Type[], thisType?: Type) {
const propagatedFlags = getPropagatingFlagsOfTypes(elementTypes, /*excludeKinds*/ 0);
const type = <TupleType>createObjectType(TypeFlags.Tuple | propagatedFlags);
type.elementTypes = elementTypes;
type.thisType = thisType;
return type;
function getTupleTypeOfArity(arity: number): GenericType {
return tupleTypes[arity] || (tupleTypes[arity] = createTupleTypeOfArity(arity));
}
function createTupleType(elementTypes: Type[]) {
return createTypeReference(getTupleTypeOfArity(elementTypes.length), elementTypes);
}
function getTypeFromTupleTypeNode(node: TupleTypeNode): Type {
@@ -5340,7 +5378,7 @@ namespace ts {
while (i > 0) {
i--;
if (isSubtypeOfAny(types[i], types)) {
types.splice(i, 1);
orderedRemoveItemAt(types, i);
}
}
}
@@ -5552,6 +5590,12 @@ namespace ts {
return nullType;
case SyntaxKind.NeverKeyword:
return neverType;
case SyntaxKind.JSDocNullKeyword:
return nullType;
case SyntaxKind.JSDocUndefinedKeyword:
return undefinedType;
case SyntaxKind.JSDocNeverKeyword:
return neverType;
case SyntaxKind.ThisType:
case SyntaxKind.ThisKeyword:
return getTypeFromThisTypeNode(node);
@@ -5845,9 +5889,6 @@ namespace ts {
if (type.flags & TypeFlags.Reference) {
return createTypeReference((<TypeReference>type).target, instantiateList((<TypeReference>type).typeArguments, mapper, instantiateType));
}
if (type.flags & TypeFlags.Tuple) {
return createTupleType(instantiateList((<TupleType>type).elementTypes, mapper, instantiateType));
}
if (type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Primitive)) {
return getUnionType(instantiateList((<UnionType>type).types, mapper, instantiateType), /*subtypeReduction*/ false, type.aliasSymbol, mapper.targetTypes);
}
@@ -6267,6 +6308,18 @@ namespace ts {
reportError(message, sourceType, targetType);
}
function tryElaborateErrorsForPrimitivesAndObjects(source: Type, target: Type) {
const sourceType = typeToString(source);
const targetType = typeToString(target);
if ((globalStringType === source && stringType === target) ||
(globalNumberType === source && numberType === target) ||
(globalBooleanType === source && booleanType === target) ||
(getGlobalESSymbolType() === source && esSymbolType === target)) {
reportError(Diagnostics._0_is_a_primitive_but_1_is_a_wrapper_object_Prefer_using_0_when_possible, targetType, sourceType);
}
}
// Compare two types and return
// Ternary.True if they are related with no assumptions,
// Ternary.Maybe if they are related with assumptions of other relationships, or
@@ -6390,6 +6443,9 @@ namespace ts {
}
if (reportErrors) {
if (source.flags & TypeFlags.ObjectType && target.flags & TypeFlags.Primitive) {
tryElaborateErrorsForPrimitivesAndObjects(source, target);
}
reportRelationError(headMessage, source, target);
}
return Ternary.False;
@@ -7168,8 +7224,8 @@ namespace ts {
* Check if a Type was written as a tuple type literal.
* Prefer using isTupleLikeType() unless the use of `elementTypes` is required.
*/
function isTupleType(type: Type): type is TupleType {
return !!(type.flags & TypeFlags.Tuple);
function isTupleType(type: Type): boolean {
return !!(type.flags & TypeFlags.Reference && (<TypeReference>type).target.flags & TypeFlags.Tuple);
}
function getFalsyFlagsOfTypes(types: Type[]): TypeFlags {
@@ -7301,11 +7357,8 @@ namespace ts {
if (type.flags & TypeFlags.Union) {
return getUnionType(map((<UnionType>type).types, getWidenedConstituentType));
}
if (isArrayType(type)) {
return createArrayType(getWidenedType((<TypeReference>type).typeArguments[0]));
}
if (isTupleType(type)) {
return createTupleType(map(type.elementTypes, getWidenedType));
if (isArrayType(type) || isTupleType(type)) {
return createTypeReference((<TypeReference>type).target, map((<TypeReference>type).typeArguments, getWidenedType));
}
}
return type;
@@ -7331,11 +7384,8 @@ namespace ts {
}
}
}
if (isArrayType(type)) {
return reportWideningErrorsInType((<TypeReference>type).typeArguments[0]);
}
if (isTupleType(type)) {
for (const t of type.elementTypes) {
if (isArrayType(type) || isTupleType(type)) {
for (const t of (<TypeReference>type).typeArguments) {
if (reportWideningErrorsInType(t)) {
errorReported = true;
}
@@ -7445,7 +7495,6 @@ namespace ts {
function couldContainTypeParameters(type: Type): boolean {
return !!(type.flags & TypeFlags.TypeParameter ||
type.flags & TypeFlags.Reference && forEach((<TypeReference>type).typeArguments, couldContainTypeParameters) ||
type.flags & TypeFlags.Tuple && forEach((<TupleType>type).elementTypes, couldContainTypeParameters) ||
type.flags & TypeFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.Class) ||
type.flags & TypeFlags.UnionOrIntersection && couldUnionOrIntersectionContainTypeParameters(<UnionOrIntersectionType>type));
}
@@ -7548,14 +7597,6 @@ namespace ts {
inferFromTypes(sourceTypes[i], targetTypes[i]);
}
}
else if (source.flags & TypeFlags.Tuple && target.flags & TypeFlags.Tuple && (<TupleType>source).elementTypes.length === (<TupleType>target).elementTypes.length) {
// If source and target are tuples of the same size, infer from element types
const sourceTypes = (<TupleType>source).elementTypes;
const targetTypes = (<TupleType>target).elementTypes;
for (let i = 0; i < sourceTypes.length; i++) {
inferFromTypes(sourceTypes[i], targetTypes[i]);
}
}
else if (target.flags & TypeFlags.UnionOrIntersection) {
const targetTypes = (<UnionOrIntersectionType>target).types;
let typeParameterCount = 0;
@@ -8717,7 +8758,7 @@ namespace ts {
// The location isn't a reference to the given symbol, meaning we're being asked
// a hypothetical question of what type the symbol would have if there was a reference
// to it at the given location. Since we have no control flow information for the
// hypotherical reference (control flow information is created and attached by the
// hypothetical reference (control flow information is created and attached by the
// binder), we simply return the declared type of the symbol.
return getTypeOfSymbol(symbol);
}
@@ -9100,10 +9141,6 @@ namespace ts {
return getInferredClassType(classSymbol);
}
}
const type = getContextuallyTypedThisType(container);
if (type) {
return type;
}
const thisType = getThisTypeOfDeclaration(container);
if (thisType) {
@@ -9344,11 +9381,11 @@ namespace ts {
}
}
function getContextuallyTypedThisType(func: FunctionLikeDeclaration): Type {
function getContextualThisParameter(func: FunctionLikeDeclaration): Symbol {
if (isContextSensitiveFunctionOrObjectLiteralMethod(func) && func.kind !== SyntaxKind.ArrowFunction) {
const contextualSignature = getContextualSignature(func);
if (contextualSignature) {
return getThisTypeOfSignature(contextualSignature);
return contextualSignature.thisParameter;
}
}
@@ -9913,7 +9950,7 @@ namespace ts {
// If array literal is actually a destructuring pattern, mark it as an implied type. We do this such
// that we get the same behavior for "var [x, y] = []" and "[x, y] = []".
if (inDestructuringPattern && elementTypes.length) {
const type = createNewTupleType(elementTypes);
const type = cloneTypeReference(createTupleType(elementTypes));
type.pattern = node;
return type;
}
@@ -9927,7 +9964,7 @@ namespace ts {
for (let i = elementTypes.length; i < patternElements.length; i++) {
const patternElement = patternElements[i];
if (hasDefaultValue(patternElement)) {
elementTypes.push((<TupleType>contextualType).elementTypes[i]);
elementTypes.push((<TypeReference>contextualType).typeArguments[i]);
}
else {
if (patternElement.kind !== SyntaxKind.OmittedExpression) {
@@ -11929,18 +11966,12 @@ namespace ts {
// Function interface, since they have none by default. This is a bit of a leap of faith
// that the user will not add any.
const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call);
const constructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct);
// TS 1.0 spec: 4.12
// If FuncExpr is of type Any, or of an object type that has no call or construct signatures
// but is a subtype of the Function interface, the call is an untyped function call. In an
// untyped function call no TypeArgs are permitted, Args can be any argument list, no contextual
// TS 1.0 Spec: 4.12
// In an untyped function call no TypeArgs are permitted, Args can be any argument list, no contextual
// types are provided for the argument expressions, and the result is always of type Any.
// We exclude union types because we may have a union of function types that happen to have
// no common signatures.
if (isTypeAny(funcType) ||
(isTypeAny(apparentType) && funcType.flags & TypeFlags.TypeParameter) ||
(!callSignatures.length && !constructSignatures.length && !(funcType.flags & TypeFlags.Union) && isTypeAssignableTo(funcType, globalFunctionType))) {
if (isUntypedFunctionCall(funcType, apparentType, callSignatures.length, constructSignatures.length)) {
// The unknownType indicates that an error already occurred (and was reported). No
// need to report another error in this case.
if (funcType !== unknownType && node.typeArguments) {
@@ -11963,6 +11994,29 @@ namespace ts {
return resolveCall(node, callSignatures, candidatesOutArray);
}
/**
* TS 1.0 spec: 4.12
* If FuncExpr is of type Any, or of an object type that has no call or construct signatures
* but is a subtype of the Function interface, the call is an untyped function call.
*/
function isUntypedFunctionCall(funcType: Type, apparentFuncType: Type, numCallSignatures: number, numConstructSignatures: number) {
if (isTypeAny(funcType)) {
return true;
}
if (isTypeAny(apparentFuncType) && funcType.flags & TypeFlags.TypeParameter) {
return true;
}
if (!numCallSignatures && !numConstructSignatures) {
// We exclude union types because we may have a union of function types that happen to have
// no common signatures.
if (funcType.flags & TypeFlags.Union) {
return false;
}
return isTypeAssignableTo(funcType, globalFunctionType);
}
return false;
}
function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[]): Signature {
if (node.arguments && languageVersion < ScriptTarget.ES5) {
const spreadIndex = getSpreadArgumentIndex(node.arguments);
@@ -12088,8 +12142,9 @@ namespace ts {
}
const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call);
const constructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct);
if (isTypeAny(tagType) || (!callSignatures.length && !(tagType.flags & TypeFlags.Union) && isTypeAssignableTo(tagType, globalFunctionType))) {
if (isUntypedFunctionCall(tagType, apparentType, callSignatures.length, constructSignatures.length)) {
return resolveUntypedCall(node);
}
@@ -12134,7 +12189,8 @@ namespace ts {
}
const callSignatures = getSignaturesOfType(apparentType, SignatureKind.Call);
if (funcType === anyType || (!callSignatures.length && !(funcType.flags & TypeFlags.Union) && isTypeAssignableTo(funcType, globalFunctionType))) {
const constructSignatures = getSignaturesOfType(apparentType, SignatureKind.Construct);
if (isUntypedFunctionCall(funcType, apparentType, callSignatures.length, constructSignatures.length)) {
return resolveUntypedCall(node);
}
@@ -12291,6 +12347,12 @@ namespace ts {
function assignContextualParameterTypes(signature: Signature, context: Signature, mapper: TypeMapper) {
const len = signature.parameters.length - (signature.hasRestParameter ? 1 : 0);
if (context.thisParameter) {
if (!signature.thisParameter) {
signature.thisParameter = createTransientSymbol(context.thisParameter, undefined);
}
assignTypeToParameterAndFixTypeParameters(signature.thisParameter, getTypeOfSymbol(context.thisParameter), mapper);
}
for (let i = 0; i < len; i++) {
const parameter = signature.parameters[i];
const contextualParameterType = getTypeAtPosition(context, i);
@@ -13038,7 +13100,7 @@ namespace ts {
// such as NodeCheckFlags.LexicalThis on "this"expression.
checkExpression(element);
if (isTupleType(sourceType)) {
error(element, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(sourceType), (<TupleType>sourceType).elementTypes.length, elements.length);
error(element, Diagnostics.Tuple_type_0_with_length_1_cannot_be_assigned_to_tuple_with_length_2, typeToString(sourceType), getTypeReferenceArity(<TypeReference>sourceType), elements.length);
}
else {
error(element, Diagnostics.Type_0_has_no_property_1, typeToString(sourceType), propName);
@@ -14126,12 +14188,7 @@ namespace ts {
checkSignatureDeclaration(node);
if (node.kind === SyntaxKind.GetAccessor) {
if (!isInAmbientContext(node) && nodeIsPresent(node.body) && (node.flags & NodeFlags.HasImplicitReturn)) {
if (node.flags & NodeFlags.HasExplicitReturn) {
if (compilerOptions.noImplicitReturns) {
error(node.name, Diagnostics.Not_all_code_paths_return_a_value);
}
}
else {
if (!(node.flags & NodeFlags.HasExplicitReturn)) {
error(node.name, Diagnostics.A_get_accessor_must_return_a_value);
}
}
@@ -14161,7 +14218,10 @@ namespace ts {
checkAccessorDeclarationTypesIdentical(node, otherAccessor, getThisTypeOfDeclaration, Diagnostics.get_and_set_accessor_must_have_the_same_this_type);
}
}
getTypeOfAccessors(getSymbolOfNode(node));
const returnType = getTypeOfAccessors(getSymbolOfNode(node));
if (node.kind === SyntaxKind.GetAccessor) {
checkAllCodePathsInNonVoidFunctionReturnOrThrow(node, returnType);
}
}
if (node.parent.kind !== SyntaxKind.ObjectLiteralExpression) {
checkSourceElement(node.body);
@@ -18517,7 +18577,7 @@ namespace ts {
else if (isTypeOfKind(type, TypeFlags.StringLike)) {
return TypeReferenceSerializationKind.StringLikeType;
}
else if (isTypeOfKind(type, TypeFlags.Tuple)) {
else if (isTupleType(type)) {
return TypeReferenceSerializationKind.ArrayLikeType;
}
else if (isTypeOfKind(type, TypeFlags.ESSymbol)) {
@@ -18728,7 +18788,13 @@ namespace ts {
(augmentations || (augmentations = [])).push(file.moduleAugmentations);
}
if (file.symbol && file.symbol.globalExports) {
mergeSymbolTable(globals, file.symbol.globalExports);
// Merge in UMD exports with first-in-wins semantics (see #9771)
const source = file.symbol.globalExports;
for (const id in source) {
if (!(id in globals)) {
globals[id] = source[id];
}
}
}
});
+1 -1
View File
@@ -885,7 +885,7 @@ namespace ts {
function convertCompilerOptionsFromJsonWorker(jsonOptions: any,
basePath: string, errors: Diagnostic[], configFileName?: string): CompilerOptions {
const options: CompilerOptions = getBaseFileName(configFileName) === "jsconfig.json" ? { allowJs: true } : {};
const options: CompilerOptions = getBaseFileName(configFileName) === "jsconfig.json" ? { allowJs: true, maxNodeModuleJsDepth: 2 } : {};
convertOptionsFromJson(optionDeclarations, jsonOptions, basePath, options, Diagnostics.Unknown_compiler_option_0, errors);
return options;
}
+29 -10
View File
@@ -1515,20 +1515,39 @@ namespace ts {
}
}
export function copyListRemovingItem<T>(item: T, list: T[]) {
const copiedList: T[] = [];
for (const e of list) {
if (e !== item) {
copiedList.push(e);
}
/** Remove an item from an array, moving everything to its right one space left. */
export function orderedRemoveItemAt<T>(array: T[], index: number): void {
// This seems to be faster than either `array.splice(i, 1)` or `array.copyWithin(i, i+ 1)`.
for (let i = index; i < array.length - 1; i++) {
array[i] = array[i + 1];
}
return copiedList;
array.pop();
}
export function createGetCanonicalFileName(useCaseSensitivefileNames: boolean): (fileName: string) => string {
return useCaseSensitivefileNames
export function unorderedRemoveItemAt<T>(array: T[], index: number): void {
// Fill in the "hole" left at `index`.
array[index] = array[array.length - 1];
array.pop();
}
/** Remove the *first* occurrence of `item` from the array. */
export function unorderedRemoveItem<T>(array: T[], item: T): void {
unorderedRemoveFirstItemWhere(array, element => element === item);
}
/** Remove the *first* element satisfying `predicate`. */
function unorderedRemoveFirstItemWhere<T>(array: T[], predicate: (element: T) => boolean): void {
for (let i = 0; i < array.length; i++) {
if (predicate(array[i])) {
unorderedRemoveItemAt(array, i);
break;
}
}
}
export function createGetCanonicalFileName(useCaseSensitiveFileNames: boolean): (fileName: string) => string {
return useCaseSensitiveFileNames
? ((fileName) => fileName)
: ((fileName) => fileName.toLowerCase());
}
}
+4 -2
View File
@@ -1132,8 +1132,10 @@ namespace ts {
// it if it's not a well known symbol. In that case, the text of the name will be exactly
// what we want, namely the name expression enclosed in brackets.
writeTextOfNode(currentText, node.name);
// If optional property emit ?
if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature || node.kind === SyntaxKind.Parameter) && hasQuestionToken(node)) {
// If optional property emit ? but in the case of parameterProperty declaration with "?" indicating optional parameter for the constructor
// we don't want to emit property declaration with "?"
if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature ||
(node.kind === SyntaxKind.Parameter && !isParameterPropertyDeclaration(node))) && hasQuestionToken(node)) {
write("?");
}
if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && node.parent.kind === SyntaxKind.TypeLiteral) {
+13 -5
View File
@@ -1955,6 +1955,10 @@
"category": "Error",
"code": 2691
},
"'{0}' is a primitive, but '{1}' is a wrapper object. Prefer using '{0}' when possible.": {
"category": "Error",
"code": 2692
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
"code": 4000
@@ -2867,11 +2871,7 @@
"Element implicitly has an 'any' type because index expression is not of type 'number'.": {
"category": "Error",
"code": 7015
},
"Property '{0}' implicitly has type 'any', because its 'set' accessor lacks a type annotation.": {
"category": "Error",
"code": 7016
},
},
"Index signature of object type implicitly has an 'any' type.": {
"category": "Error",
"code": 7017
@@ -2928,6 +2928,14 @@
"category": "Error",
"code": 7031
},
"Property '{0}' implicitly has type 'any', because its set accessor lacks a parameter type annotation.": {
"category": "Error",
"code": 7032
},
"Property '{0}' implicitly has type 'any', because its get accessor lacks a return type annotation.": {
"category": "Error",
"code": 7033
},
"You cannot rename this element.": {
"category": "Error",
"code": 8000
+5 -1
View File
@@ -1817,6 +1817,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
else if (node.parent.kind === SyntaxKind.ConditionalExpression && (<ConditionalExpression>node.parent).condition === node) {
return true;
}
else if (node.parent.kind === SyntaxKind.PrefixUnaryExpression || node.parent.kind === SyntaxKind.DeleteExpression ||
node.parent.kind === SyntaxKind.TypeOfExpression || node.parent.kind === SyntaxKind.VoidExpression) {
return true;
}
return false;
}
@@ -6583,7 +6587,7 @@ const _super = (function (geti, seti) {
// import { x, y } from "foo"
// import d, * as x from "foo"
// import d, { x, y } from "foo"
const isNakedImport = SyntaxKind.ImportDeclaration && !(<ImportDeclaration>node).importClause;
const isNakedImport = node.kind === SyntaxKind.ImportDeclaration && !(<ImportDeclaration>node).importClause;
if (!isNakedImport) {
write(varOrConst);
write(getGeneratedNameForNode(<ImportDeclaration>node));
+40 -17
View File
@@ -912,7 +912,7 @@ namespace ts {
// Note: it is not actually necessary to save/restore the context flags here. That's
// because the saving/restoring of these flags happens naturally through the recursive
// descent nature of our parser. However, we still store this here just so we can
// assert that that invariant holds.
// assert that invariant holds.
const saveContextFlags = contextFlags;
// If we're only looking ahead, then tell the scanner to only lookahead as well.
@@ -2339,6 +2339,7 @@ namespace ts {
token() === SyntaxKind.LessThanToken ||
token() === SyntaxKind.QuestionToken ||
token() === SyntaxKind.ColonToken ||
token() === SyntaxKind.CommaToken ||
canParseSemicolon();
}
return false;
@@ -2765,7 +2766,7 @@ namespace ts {
// Note: for ease of implementation we treat productions '2' and '3' as the same thing.
// (i.e. they're both BinaryExpressions with an assignment operator in it).
// First, do the simple check if we have a YieldExpression (production '5').
// First, do the simple check if we have a YieldExpression (production '6').
if (isYieldExpression()) {
return parseYieldExpression();
}
@@ -3373,24 +3374,40 @@ namespace ts {
}
/**
* Parse ES7 unary expression and await expression
* Parse ES7 exponential expression and await expression
*
* ES7 ExponentiationExpression:
* 1) UnaryExpression[?Yield]
* 2) UpdateExpression[?Yield] ** ExponentiationExpression[?Yield]
*
* ES7 UnaryExpression:
* 1) SimpleUnaryExpression[?yield]
* 2) IncrementExpression[?yield] ** UnaryExpression[?yield]
*/
function parseUnaryExpressionOrHigher(): UnaryExpression | BinaryExpression {
if (isAwaitExpression()) {
return parseAwaitExpression();
}
if (isIncrementExpression()) {
/**
* ES7 UpdateExpression:
* 1) LeftHandSideExpression[?Yield]
* 2) LeftHandSideExpression[?Yield][no LineTerminator here]++
* 3) LeftHandSideExpression[?Yield][no LineTerminator here]--
* 4) ++UnaryExpression[?Yield]
* 5) --UnaryExpression[?Yield]
*/
if (isUpdateExpression()) {
const incrementExpression = parseIncrementExpression();
return token() === SyntaxKind.AsteriskAsteriskToken ?
<BinaryExpression>parseBinaryExpressionRest(getBinaryOperatorPrecedence(), incrementExpression) :
incrementExpression;
}
/**
* ES7 UnaryExpression:
* 1) UpdateExpression[?yield]
* 2) delete UpdateExpression[?yield]
* 3) void UpdateExpression[?yield]
* 4) typeof UpdateExpression[?yield]
* 5) + UpdateExpression[?yield]
* 6) - UpdateExpression[?yield]
* 7) ~ UpdateExpression[?yield]
* 8) ! UpdateExpression[?yield]
*/
const unaryOperator = token();
const simpleUnaryExpression = parseSimpleUnaryExpression();
if (token() === SyntaxKind.AsteriskAsteriskToken) {
@@ -3408,8 +3425,8 @@ namespace ts {
/**
* Parse ES7 simple-unary expression or higher:
*
* ES7 SimpleUnaryExpression:
* 1) IncrementExpression[?yield]
* ES7 UnaryExpression:
* 1) UpdateExpression[?yield]
* 2) delete UnaryExpression[?yield]
* 3) void UnaryExpression[?yield]
* 4) typeof UnaryExpression[?yield]
@@ -3432,13 +3449,15 @@ namespace ts {
return parseTypeOfExpression();
case SyntaxKind.VoidKeyword:
return parseVoidExpression();
case SyntaxKind.AwaitKeyword:
return parseAwaitExpression();
case SyntaxKind.LessThanToken:
// This is modified UnaryExpression grammar in TypeScript
// UnaryExpression (modified):
// < type > UnaryExpression
return parseTypeAssertion();
case SyntaxKind.AwaitKeyword:
if (isAwaitExpression()) {
return parseAwaitExpression();
}
default:
return parseIncrementExpression();
}
@@ -3447,14 +3466,14 @@ namespace ts {
/**
* Check if the current token can possibly be an ES7 increment expression.
*
* ES7 IncrementExpression:
* ES7 UpdateExpression:
* LeftHandSideExpression[?Yield]
* LeftHandSideExpression[?Yield][no LineTerminator here]++
* LeftHandSideExpression[?Yield][no LineTerminator here]--
* ++LeftHandSideExpression[?Yield]
* --LeftHandSideExpression[?Yield]
*/
function isIncrementExpression(): boolean {
function isUpdateExpression(): boolean {
// This function is called inside parseUnaryExpression to decide
// whether to call parseSimpleUnaryExpression or call parseIncrementExpression directly
switch (token()) {
@@ -3465,6 +3484,7 @@ namespace ts {
case SyntaxKind.DeleteKeyword:
case SyntaxKind.TypeOfKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.AwaitKeyword:
return false;
case SyntaxKind.LessThanToken:
// If we are not in JSX context, we are parsing TypeAssertion which is an UnaryExpression
@@ -5893,6 +5913,9 @@ namespace ts {
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.NullKeyword:
case SyntaxKind.UndefinedKeyword:
case SyntaxKind.NeverKeyword:
return parseTokenNode<JSDocType>();
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
+4 -3
View File
@@ -720,8 +720,9 @@ namespace ts {
const typesFile = tryReadTypesSection(packageJsonPath, candidate, state);
if (typesFile) {
const onlyRecordFailures = !directoryProbablyExists(getDirectoryPath(typesFile), state.host);
// The package.json "typings" property must specify the file with extension, so just try that exact filename.
const result = tryFile(typesFile, failedLookupLocation, onlyRecordFailures, state);
// A package.json "typings" may specify an exact filename, or may choose to omit an extension.
const result = tryFile(typesFile, failedLookupLocation, onlyRecordFailures, state) ||
tryAddingExtensions(typesFile, extensions, failedLookupLocation, onlyRecordFailures, state);
if (result) {
return result;
}
@@ -1100,7 +1101,7 @@ namespace ts {
// - This calls resolveModuleNames, and then calls findSourceFile for each resolved module.
// As all these operations happen - and are nested - within the createProgram call, they close over the below variables.
// The current resolution depth is tracked by incrementing/decrementing as the depth first search progresses.
const maxNodeModulesJsDepth = typeof options.maxNodeModuleJsDepth === "number" ? options.maxNodeModuleJsDepth : 2;
const maxNodeModulesJsDepth = typeof options.maxNodeModuleJsDepth === "number" ? options.maxNodeModuleJsDepth : 0;
let currentNodeModulesDepth = 0;
// If a module has some of its imports skipped due to being at the depth limit under node_modules, then track
+2 -5
View File
@@ -285,13 +285,10 @@ namespace ts {
function removeFileWatcherCallback(filePath: string, callback: FileWatcherCallback) {
const callbacks = fileWatcherCallbacks[filePath];
if (callbacks) {
const newCallbacks = copyListRemovingItem(callback, callbacks);
if (newCallbacks.length === 0) {
unorderedRemoveItem(callbacks, callback);
if (callbacks.length === 0) {
delete fileWatcherCallbacks[filePath];
}
else {
fileWatcherCallbacks[filePath] = newCallbacks;
}
}
}
+1 -4
View File
@@ -489,10 +489,7 @@ namespace ts {
sourceFile.fileWatcher.close();
sourceFile.fileWatcher = undefined;
if (removed) {
const index = rootFileNames.indexOf(sourceFile.fileName);
if (index >= 0) {
rootFileNames.splice(index, 1);
}
unorderedRemoveItem(rootFileNames, sourceFile.fileName);
}
startTimerForRecompilation();
}
+5 -7
View File
@@ -351,6 +351,9 @@ namespace ts {
JSDocPropertyTag,
JSDocTypeLiteral,
JSDocLiteralType,
JSDocNullKeyword,
JSDocUndefinedKeyword,
JSDocNeverKeyword,
// Synthesized list
SyntaxList,
@@ -383,7 +386,7 @@ namespace ts {
FirstJSDocNode = JSDocTypeExpression,
LastJSDocNode = JSDocLiteralType,
FirstJSDocTagNode = JSDocComment,
LastJSDocTagNode = JSDocLiteralType
LastJSDocTagNode = JSDocNeverKeyword
}
export const enum NodeFlags {
@@ -2263,7 +2266,7 @@ namespace ts {
Class = 1 << 15, // Class
Interface = 1 << 16, // Interface
Reference = 1 << 17, // Generic type reference
Tuple = 1 << 18, // Tuple
Tuple = 1 << 18, // Synthesized generic tuple type
Union = 1 << 19, // Union (T | U)
Intersection = 1 << 20, // Intersection (T & U)
Anonymous = 1 << 21, // Anonymous
@@ -2385,11 +2388,6 @@ namespace ts {
instantiations: Map<TypeReference>; // Generic instantiation cache
}
export interface TupleType extends ObjectType {
elementTypes: Type[]; // Element types
thisType?: Type; // This-type of tuple (only needed for tuples that are constraints of type parameters)
}
export interface UnionOrIntersectionType extends Type {
types: Type[]; // Constituent types
/* @internal */
+26 -3
View File
@@ -301,6 +301,10 @@ namespace ts {
return node.kind >= SyntaxKind.FirstJSDocNode && node.kind <= SyntaxKind.LastJSDocNode;
}
export function isJSDocTag(node: Node) {
return node.kind >= SyntaxKind.FirstJSDocTagNode && node.kind <= SyntaxKind.LastJSDocTagNode;
}
export function getNonDecoratorTokenPosOfNode(node: Node, sourceFile?: SourceFile): number {
if (nodeIsMissing(node) || !node.decorators) {
return getTokenPosOfNode(node, sourceFile);
@@ -1031,6 +1035,18 @@ namespace ts {
return undefined;
}
export function isCallLikeExpression(node: Node): node is CallLikeExpression {
switch (node.kind) {
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
case SyntaxKind.TaggedTemplateExpression:
case SyntaxKind.Decorator:
return true;
default:
return false;
}
}
export function getInvokedExpression(node: CallLikeExpression): Expression {
if (node.kind === SyntaxKind.TaggedTemplateExpression) {
return (<TaggedTemplateExpression>node).tag;
@@ -2655,10 +2671,17 @@ namespace ts {
return token >= SyntaxKind.FirstAssignment && token <= SyntaxKind.LastAssignment;
}
export function isExpressionWithTypeArgumentsInClassExtendsClause(node: Node): boolean {
return node.kind === SyntaxKind.ExpressionWithTypeArguments &&
/** Get `C` given `N` if `N` is in the position `class C extends N` where `N` is an ExpressionWithTypeArguments. */
export function tryGetClassExtendingExpressionWithTypeArguments(node: Node): ClassLikeDeclaration | undefined {
if (node.kind === SyntaxKind.ExpressionWithTypeArguments &&
(<HeritageClause>node.parent).token === SyntaxKind.ExtendsKeyword &&
isClassLike(node.parent.parent);
isClassLike(node.parent.parent)) {
return node.parent.parent;
}
}
export function isExpressionWithTypeArgumentsInClassExtendsClause(node: Node): boolean {
return tryGetClassExtendingExpressionWithTypeArguments(node) !== undefined;
}
export function isEntityNameExpression(node: Expression): node is EntityNameExpression {
+9 -217
View File
@@ -1,8 +1,6 @@
/// <reference path="harness.ts" />
/// <reference path="runnerbase.ts" />
/// <reference path="typeWriter.ts" />
// In harness baselines, null is different than undefined. See `generateActual` in `harness.ts`.
/* tslint:disable:no-null-keyword */
const enum CompilerTestType {
Conformance,
@@ -136,27 +134,16 @@ class CompilerBaselineRunner extends RunnerBase {
otherFiles = undefined;
});
function getByteOrderMarkText(file: Harness.Compiler.GeneratedFile): string {
return file.writeByteOrderMark ? "\u00EF\u00BB\u00BF" : "";
}
function getErrorBaseline(toBeCompiled: Harness.Compiler.TestFile[], otherFiles: Harness.Compiler.TestFile[], result: Harness.Compiler.CompilerResult) {
return Harness.Compiler.getErrorBaseline(toBeCompiled.concat(otherFiles), result.errors);
}
// check errors
it("Correct errors for " + fileName, () => {
if (this.errors) {
Harness.Baseline.runBaseline("Correct errors for " + fileName, justName.replace(/\.tsx?$/, ".errors.txt"), (): string => {
if (result.errors.length === 0) return null;
return getErrorBaseline(toBeCompiled, otherFiles, result);
});
Harness.Compiler.doErrorBaseline(justName, toBeCompiled.concat(otherFiles), result.errors);
}
});
it (`Correct module resolution tracing for ${fileName}`, () => {
if (options.traceResolution) {
Harness.Baseline.runBaseline("Correct module resolution tracing for " + fileName, justName.replace(/\.tsx?$/, ".trace.json"), () => {
Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".trace.json"), () => {
return JSON.stringify(result.traceResults || [], undefined, 4);
});
}
@@ -165,11 +152,13 @@ class CompilerBaselineRunner extends RunnerBase {
// Source maps?
it("Correct sourcemap content for " + fileName, () => {
if (options.sourceMap || options.inlineSourceMap) {
Harness.Baseline.runBaseline("Correct sourcemap content for " + fileName, justName.replace(/\.tsx?$/, ".sourcemap.txt"), () => {
Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".sourcemap.txt"), () => {
const record = result.getSourceMapRecord();
if (options.noEmitOnError && result.errors.length !== 0 && record === undefined) {
// Because of the noEmitOnError option no files are created. We need to return null because baselining isn"t required.
// Because of the noEmitOnError option no files are created. We need to return null because baselining isn't required.
/* tslint:disable:no-null-keyword */
return null;
/* tslint:enable:no-null-keyword */
}
return record;
});
@@ -178,87 +167,12 @@ class CompilerBaselineRunner extends RunnerBase {
it("Correct JS output for " + fileName, () => {
if (hasNonDtsFiles && this.emit) {
if (!options.noEmit && result.files.length === 0 && result.errors.length === 0) {
throw new Error("Expected at least one js file to be emitted or at least one error to be created.");
}
// check js output
Harness.Baseline.runBaseline("Correct JS output for " + fileName, justName.replace(/\.tsx?/, ".js"), () => {
let tsCode = "";
const tsSources = otherFiles.concat(toBeCompiled);
if (tsSources.length > 1) {
tsCode += "//// [" + fileName + "] ////\r\n\r\n";
}
for (let i = 0; i < tsSources.length; i++) {
tsCode += "//// [" + Harness.Path.getFileName(tsSources[i].unitName) + "]\r\n";
tsCode += tsSources[i].content + (i < (tsSources.length - 1) ? "\r\n" : "");
}
let jsCode = "";
for (let i = 0; i < result.files.length; i++) {
jsCode += "//// [" + Harness.Path.getFileName(result.files[i].fileName) + "]\r\n";
jsCode += getByteOrderMarkText(result.files[i]);
jsCode += result.files[i].code;
}
if (result.declFilesCode.length > 0) {
jsCode += "\r\n\r\n";
for (let i = 0; i < result.declFilesCode.length; i++) {
jsCode += "//// [" + Harness.Path.getFileName(result.declFilesCode[i].fileName) + "]\r\n";
jsCode += getByteOrderMarkText(result.declFilesCode[i]);
jsCode += result.declFilesCode[i].code;
}
}
const declFileCompilationResult =
Harness.Compiler.compileDeclarationFiles(
toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined);
if (declFileCompilationResult && declFileCompilationResult.declResult.errors.length) {
jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n";
jsCode += "\r\n\r\n";
jsCode += getErrorBaseline(declFileCompilationResult.declInputFiles, declFileCompilationResult.declOtherFiles, declFileCompilationResult.declResult);
}
if (jsCode.length > 0) {
return tsCode + "\r\n\r\n" + jsCode;
}
else {
return null;
}
});
Harness.Compiler.doJsEmitBaseline(justName, fileName, options, result, toBeCompiled, otherFiles, harnessSettings);
}
});
it("Correct Sourcemap output for " + fileName, () => {
if (options.inlineSourceMap) {
if (result.sourceMaps.length > 0) {
throw new Error("No sourcemap files should be generated if inlineSourceMaps was set.");
}
return null;
}
else if (options.sourceMap) {
if (result.sourceMaps.length !== result.files.length) {
throw new Error("Number of sourcemap files should be same as js files.");
}
Harness.Baseline.runBaseline("Correct Sourcemap output for " + fileName, justName.replace(/\.tsx?/, ".js.map"), () => {
if (options.noEmitOnError && result.errors.length !== 0 && result.sourceMaps.length === 0) {
// We need to return null here or the runBaseLine will actually create a empty file.
// Baselining isn't required here because there is no output.
return null;
}
let sourceMapCode = "";
for (let i = 0; i < result.sourceMaps.length; i++) {
sourceMapCode += "//// [" + Harness.Path.getFileName(result.sourceMaps[i].fileName) + "]\r\n";
sourceMapCode += getByteOrderMarkText(result.sourceMaps[i]);
sourceMapCode += result.sourceMaps[i].code;
}
return sourceMapCode;
});
}
Harness.Compiler.doSourcemapBaseline(justName, options, result);
});
it("Correct type/symbol baselines for " + fileName, () => {
@@ -266,129 +180,7 @@ class CompilerBaselineRunner extends RunnerBase {
return;
}
// NEWTODO: Type baselines
if (result.errors.length !== 0) {
return;
}
// The full walker simulates the types that you would get from doing a full
// compile. The pull walker simulates the types you get when you just do
// a type query for a random node (like how the LS would do it). Most of the
// time, these will be the same. However, occasionally, they can be different.
// Specifically, when the compiler internally depends on symbol IDs to order
// things, then we may see different results because symbols can be created in a
// different order with 'pull' operations, and thus can produce slightly differing
// output.
//
// For example, with a full type check, we may see a type displayed as: number | string
// But with a pull type check, we may see it as: string | number
//
// These types are equivalent, but depend on what order the compiler observed
// certain parts of the program.
const program = result.program;
const allFiles = toBeCompiled.concat(otherFiles).filter(file => !!program.getSourceFile(file.unitName));
const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true);
const fullResults = ts.createMap<TypeWriterResult[]>();
const pullResults = ts.createMap<TypeWriterResult[]>();
for (const sourceFile of allFiles) {
fullResults[sourceFile.unitName] = fullWalker.getTypeAndSymbols(sourceFile.unitName);
pullResults[sourceFile.unitName] = fullWalker.getTypeAndSymbols(sourceFile.unitName);
}
// Produce baselines. The first gives the types for all expressions.
// The second gives symbols for all identifiers.
let e1: Error, e2: Error;
try {
checkBaseLines(/*isSymbolBaseLine*/ false);
}
catch (e) {
e1 = e;
}
try {
checkBaseLines(/*isSymbolBaseLine*/ true);
}
catch (e) {
e2 = e;
}
if (e1 || e2) {
throw e1 || e2;
}
return;
function checkBaseLines(isSymbolBaseLine: boolean) {
const fullBaseLine = generateBaseLine(fullResults, isSymbolBaseLine);
const pullBaseLine = generateBaseLine(pullResults, isSymbolBaseLine);
const fullExtension = isSymbolBaseLine ? ".symbols" : ".types";
const pullExtension = isSymbolBaseLine ? ".symbols.pull" : ".types.pull";
if (fullBaseLine !== pullBaseLine) {
Harness.Baseline.runBaseline("Correct full information for " + fileName, justName.replace(/\.tsx?/, fullExtension), () => fullBaseLine);
Harness.Baseline.runBaseline("Correct pull information for " + fileName, justName.replace(/\.tsx?/, pullExtension), () => pullBaseLine);
}
else {
Harness.Baseline.runBaseline("Correct information for " + fileName, justName.replace(/\.tsx?/, fullExtension), () => fullBaseLine);
}
}
function generateBaseLine(typeWriterResults: ts.Map<TypeWriterResult[]>, isSymbolBaseline: boolean): string {
const typeLines: string[] = [];
const typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {};
allFiles.forEach(file => {
const codeLines = file.content.split("\n");
typeWriterResults[file.unitName].forEach(result => {
if (isSymbolBaseline && !result.symbol) {
return;
}
const typeOrSymbolString = isSymbolBaseline ? result.symbol : result.type;
const formattedLine = result.sourceText.replace(/\r?\n/g, "") + " : " + typeOrSymbolString;
if (!typeMap[file.unitName]) {
typeMap[file.unitName] = {};
}
let typeInfo = [formattedLine];
const existingTypeInfo = typeMap[file.unitName][result.line];
if (existingTypeInfo) {
typeInfo = existingTypeInfo.concat(typeInfo);
}
typeMap[file.unitName][result.line] = typeInfo;
});
typeLines.push("=== " + file.unitName + " ===\r\n");
for (let i = 0; i < codeLines.length; i++) {
const currentCodeLine = codeLines[i];
typeLines.push(currentCodeLine + "\r\n");
if (typeMap[file.unitName]) {
const typeInfo = typeMap[file.unitName][i];
if (typeInfo) {
typeInfo.forEach(ty => {
typeLines.push(">" + ty + "\r\n");
});
if (i + 1 < codeLines.length && (codeLines[i + 1].match(/^\s*[{|}]\s*$/) || codeLines[i + 1].trim() === "")) {
}
else {
typeLines.push("\r\n");
}
}
}
else {
typeLines.push("No type information for this code.");
}
}
});
return typeLines.join("");
}
Harness.Compiler.doTypeAndSymbolBaseline(justName, result, toBeCompiled.concat(otherFiles).filter(file => !!result.program.getSourceFile(file.unitName)));
});
});
}
+48 -32
View File
@@ -206,6 +206,24 @@ namespace FourSlash {
private inputFiles = ts.createMap<string>(); // Map between inputFile's fileName and its content for easily looking up when resolving references
private static getDisplayPartsJson(displayParts: ts.SymbolDisplayPart[]) {
let result = "";
ts.forEach(displayParts, part => {
if (result) {
result += ",\n ";
}
else {
result = "[\n ";
}
result += JSON.stringify(part);
});
if (result) {
result += "\n]";
}
return result;
}
// Add input file which has matched file name with the given reference-file path.
// This is necessary when resolveReference flag is specified
private addMatchedInputFile(referenceFilePath: string, extensions: string[]) {
@@ -777,6 +795,20 @@ namespace FourSlash {
ts.forEachProperty(this.rangesByText(), ranges => this.verifyRangesReferenceEachOther(ranges));
}
public verifyDisplayPartsOfReferencedSymbol(expected: ts.SymbolDisplayPart[]) {
const referencedSymbols = this.findReferencesAtCaret();
if (referencedSymbols.length === 0) {
this.raiseError("No referenced symbols found at current caret position");
}
else if (referencedSymbols.length > 1) {
this.raiseError("More than one referenced symbol found");
}
assert.equal(TestState.getDisplayPartsJson(referencedSymbols[0].definition.displayParts),
TestState.getDisplayPartsJson(expected), this.messageAtLastKnownMarker("referenced symbol definition display parts"));
}
private verifyReferencesWorker(references: ts.ReferenceEntry[], fileName: string, start: number, end: number, isWriteAccess?: boolean, isDefinition?: boolean) {
for (let i = 0; i < references.length; i++) {
const reference = references[i];
@@ -811,6 +843,10 @@ namespace FourSlash {
return this.languageService.getReferencesAtPosition(this.activeFile.fileName, this.currentCaretPosition);
}
private findReferencesAtCaret() {
return this.languageService.findReferences(this.activeFile.fileName, this.currentCaretPosition);
}
public getSyntacticDiagnostics(expected: string) {
const diagnostics = this.languageService.getSyntacticDiagnostics(this.activeFile.fileName);
this.testDiagnostics(expected, diagnostics);
@@ -856,30 +892,12 @@ namespace FourSlash {
displayParts: ts.SymbolDisplayPart[],
documentation: ts.SymbolDisplayPart[]) {
function getDisplayPartsJson(displayParts: ts.SymbolDisplayPart[]) {
let result = "";
ts.forEach(displayParts, part => {
if (result) {
result += ",\n ";
}
else {
result = "[\n ";
}
result += JSON.stringify(part);
});
if (result) {
result += "\n]";
}
return result;
}
const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition);
assert.equal(actualQuickInfo.kind, kind, this.messageAtLastKnownMarker("QuickInfo kind"));
assert.equal(actualQuickInfo.kindModifiers, kindModifiers, this.messageAtLastKnownMarker("QuickInfo kindModifiers"));
assert.equal(JSON.stringify(actualQuickInfo.textSpan), JSON.stringify(textSpan), this.messageAtLastKnownMarker("QuickInfo textSpan"));
assert.equal(getDisplayPartsJson(actualQuickInfo.displayParts), getDisplayPartsJson(displayParts), this.messageAtLastKnownMarker("QuickInfo displayParts"));
assert.equal(getDisplayPartsJson(actualQuickInfo.documentation), getDisplayPartsJson(documentation), this.messageAtLastKnownMarker("QuickInfo documentation"));
assert.equal(TestState.getDisplayPartsJson(actualQuickInfo.displayParts), TestState.getDisplayPartsJson(displayParts), this.messageAtLastKnownMarker("QuickInfo displayParts"));
assert.equal(TestState.getDisplayPartsJson(actualQuickInfo.documentation), TestState.getDisplayPartsJson(documentation), this.messageAtLastKnownMarker("QuickInfo documentation"));
}
public verifyRenameLocations(findInStrings: boolean, findInComments: boolean, ranges?: Range[]) {
@@ -1132,12 +1150,10 @@ namespace FourSlash {
}
Harness.Baseline.runBaseline(
"Breakpoint Locations for " + this.activeFile.fileName,
baselineFile,
() => {
return this.baselineCurrentFileLocations(pos => this.getBreakpointStatementLocation(pos));
},
true /* run immediately */);
});
}
public baselineGetEmitOutput() {
@@ -1159,7 +1175,6 @@ namespace FourSlash {
}
Harness.Baseline.runBaseline(
"Generate getEmitOutput baseline : " + emitFiles.join(" "),
this.testData.globalOptions[metadataOptionNames.baselineFile],
() => {
let resultString = "";
@@ -1185,8 +1200,7 @@ namespace FourSlash {
});
return resultString;
},
true /* run immediately */);
});
}
public printBreakpointLocation(pos: number) {
@@ -1550,7 +1564,7 @@ namespace FourSlash {
public goToDefinition(definitionIndex: number) {
const definitions = this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition);
if (!definitions || !definitions.length) {
this.raiseError("goToDefinition failed - expected to at least one definition location but got 0");
this.raiseError("goToDefinition failed - expected to find at least one definition location but got 0");
}
if (definitionIndex >= definitions.length) {
@@ -1565,7 +1579,7 @@ namespace FourSlash {
public goToTypeDefinition(definitionIndex: number) {
const definitions = this.languageService.getTypeDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition);
if (!definitions || !definitions.length) {
this.raiseError("goToTypeDefinition failed - expected to at least one definition location but got 0");
this.raiseError("goToTypeDefinition failed - expected to find at least one definition location but got 0");
}
if (definitionIndex >= definitions.length) {
@@ -1586,7 +1600,7 @@ namespace FourSlash {
this.raiseError(`goToDefinition - expected to 0 definition locations but got ${definitions.length}`);
}
else if (!foundDefinitions && !negative) {
this.raiseError("goToDefinition - expected to at least one definition location but got 0");
this.raiseError("goToDefinition - expected to find at least one definition location but got 0");
}
}
@@ -1729,13 +1743,11 @@ namespace FourSlash {
public baselineCurrentFileNameOrDottedNameSpans() {
Harness.Baseline.runBaseline(
"Name OrDottedNameSpans for " + this.activeFile.fileName,
this.testData.globalOptions[metadataOptionNames.baselineFile],
() => {
return this.baselineCurrentFileLocations(pos =>
this.getNameOrDottedNameSpan(pos));
},
true /* run immediately */);
});
}
public printNameOrDottedNameSpans(pos: number) {
@@ -2952,6 +2964,10 @@ namespace FourSlashInterface {
this.state.verifyRangesReferenceEachOther(ranges);
}
public findReferencesDefinitionDisplayPartsAtCaretAre(expected: ts.SymbolDisplayPart[]) {
this.state.verifyDisplayPartsOfReferencedSymbol(expected);
}
public rangesWithSameTextReferenceEachOther() {
this.state.verifyRangesWithSameTextReferenceEachOther();
}
+262 -51
View File
@@ -1328,6 +1328,233 @@ namespace Harness {
Harness.IO.newLine() + Harness.IO.newLine() + outputLines.join("\r\n");
}
export function doErrorBaseline(baselinePath: string, inputFiles: TestFile[], errors: ts.Diagnostic[]) {
Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?$/, ".errors.txt"), (): string => {
if (errors.length === 0) {
/* tslint:disable:no-null-keyword */
return null;
/* tslint:enable:no-null-keyword */
}
return getErrorBaseline(inputFiles, errors);
});
}
export function doTypeAndSymbolBaseline(baselinePath: string, result: CompilerResult, allFiles: {unitName: string, content: string}[], opts?: Harness.Baseline.BaselineOptions) {
if (result.errors.length !== 0) {
return;
}
// The full walker simulates the types that you would get from doing a full
// compile. The pull walker simulates the types you get when you just do
// a type query for a random node (like how the LS would do it). Most of the
// time, these will be the same. However, occasionally, they can be different.
// Specifically, when the compiler internally depends on symbol IDs to order
// things, then we may see different results because symbols can be created in a
// different order with 'pull' operations, and thus can produce slightly differing
// output.
//
// For example, with a full type check, we may see a type displayed as: number | string
// But with a pull type check, we may see it as: string | number
//
// These types are equivalent, but depend on what order the compiler observed
// certain parts of the program.
const program = result.program;
const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true);
const fullResults = ts.createMap<TypeWriterResult[]>();
for (const sourceFile of allFiles) {
fullResults[sourceFile.unitName] = fullWalker.getTypeAndSymbols(sourceFile.unitName);
}
// Produce baselines. The first gives the types for all expressions.
// The second gives symbols for all identifiers.
let typesError: Error, symbolsError: Error;
try {
checkBaseLines(/*isSymbolBaseLine*/ false);
}
catch (e) {
typesError = e;
}
try {
checkBaseLines(/*isSymbolBaseLine*/ true);
}
catch (e) {
symbolsError = e;
}
if (typesError && symbolsError) {
throw new Error(typesError.message + ts.sys.newLine + symbolsError.message);
}
if (typesError) {
throw typesError;
}
if (symbolsError) {
throw symbolsError;
}
return;
function checkBaseLines(isSymbolBaseLine: boolean) {
const fullBaseLine = generateBaseLine(fullResults, isSymbolBaseLine);
const fullExtension = isSymbolBaseLine ? ".symbols" : ".types";
// When calling this function from rwc-runner, the baselinePath will have no extension.
// As rwc test- file is stored in json which ".json" will get stripped off.
// When calling this function from compiler-runner, the baselinePath will then has either ".ts" or ".tsx" extension
const outputFileName = ts.endsWith(baselinePath, ".ts") || ts.endsWith(baselinePath, ".tsx") ?
baselinePath.replace(/\.tsx?/, fullExtension) : baselinePath.concat(fullExtension);
Harness.Baseline.runBaseline(outputFileName, () => fullBaseLine, opts);
}
function generateBaseLine(typeWriterResults: ts.Map<TypeWriterResult[]>, isSymbolBaseline: boolean): string {
const typeLines: string[] = [];
const typeMap: { [fileName: string]: { [lineNum: number]: string[]; } } = {};
allFiles.forEach(file => {
const codeLines = file.content.split("\n");
typeWriterResults[file.unitName].forEach(result => {
if (isSymbolBaseline && !result.symbol) {
return;
}
const typeOrSymbolString = isSymbolBaseline ? result.symbol : result.type;
const formattedLine = result.sourceText.replace(/\r?\n/g, "") + " : " + typeOrSymbolString;
if (!typeMap[file.unitName]) {
typeMap[file.unitName] = {};
}
let typeInfo = [formattedLine];
const existingTypeInfo = typeMap[file.unitName][result.line];
if (existingTypeInfo) {
typeInfo = existingTypeInfo.concat(typeInfo);
}
typeMap[file.unitName][result.line] = typeInfo;
});
typeLines.push("=== " + file.unitName + " ===\r\n");
for (let i = 0; i < codeLines.length; i++) {
const currentCodeLine = codeLines[i];
typeLines.push(currentCodeLine + "\r\n");
if (typeMap[file.unitName]) {
const typeInfo = typeMap[file.unitName][i];
if (typeInfo) {
typeInfo.forEach(ty => {
typeLines.push(">" + ty + "\r\n");
});
if (i + 1 < codeLines.length && (codeLines[i + 1].match(/^\s*[{|}]\s*$/) || codeLines[i + 1].trim() === "")) {
}
else {
typeLines.push("\r\n");
}
}
}
else {
typeLines.push("No type information for this code.");
}
}
});
return typeLines.join("");
}
}
function getByteOrderMarkText(file: Harness.Compiler.GeneratedFile): string {
return file.writeByteOrderMark ? "\u00EF\u00BB\u00BF" : "";
}
export function doSourcemapBaseline(baselinePath: string, options: ts.CompilerOptions, result: CompilerResult) {
if (options.inlineSourceMap) {
if (result.sourceMaps.length > 0) {
throw new Error("No sourcemap files should be generated if inlineSourceMaps was set.");
}
return;
}
else if (options.sourceMap) {
if (result.sourceMaps.length !== result.files.length) {
throw new Error("Number of sourcemap files should be same as js files.");
}
Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?/, ".js.map"), () => {
if (options.noEmitOnError && result.errors.length !== 0 && result.sourceMaps.length === 0) {
// We need to return null here or the runBaseLine will actually create a empty file.
// Baselining isn't required here because there is no output.
/* tslint:disable:no-null-keyword */
return null;
/* tslint:enable:no-null-keyword */
}
let sourceMapCode = "";
for (let i = 0; i < result.sourceMaps.length; i++) {
sourceMapCode += "//// [" + Harness.Path.getFileName(result.sourceMaps[i].fileName) + "]\r\n";
sourceMapCode += getByteOrderMarkText(result.sourceMaps[i]);
sourceMapCode += result.sourceMaps[i].code;
}
return sourceMapCode;
});
}
}
export function doJsEmitBaseline(baselinePath: string, header: string, options: ts.CompilerOptions, result: CompilerResult, toBeCompiled: Harness.Compiler.TestFile[], otherFiles: Harness.Compiler.TestFile[], harnessSettings: Harness.TestCaseParser.CompilerSettings) {
if (!options.noEmit && result.files.length === 0 && result.errors.length === 0) {
throw new Error("Expected at least one js file to be emitted or at least one error to be created.");
}
// check js output
Harness.Baseline.runBaseline(baselinePath.replace(/\.tsx?/, ".js"), () => {
let tsCode = "";
const tsSources = otherFiles.concat(toBeCompiled);
if (tsSources.length > 1) {
tsCode += "//// [" + header + "] ////\r\n\r\n";
}
for (let i = 0; i < tsSources.length; i++) {
tsCode += "//// [" + Harness.Path.getFileName(tsSources[i].unitName) + "]\r\n";
tsCode += tsSources[i].content + (i < (tsSources.length - 1) ? "\r\n" : "");
}
let jsCode = "";
for (let i = 0; i < result.files.length; i++) {
jsCode += "//// [" + Harness.Path.getFileName(result.files[i].fileName) + "]\r\n";
jsCode += getByteOrderMarkText(result.files[i]);
jsCode += result.files[i].code;
}
if (result.declFilesCode.length > 0) {
jsCode += "\r\n\r\n";
for (let i = 0; i < result.declFilesCode.length; i++) {
jsCode += "//// [" + Harness.Path.getFileName(result.declFilesCode[i].fileName) + "]\r\n";
jsCode += getByteOrderMarkText(result.declFilesCode[i]);
jsCode += result.declFilesCode[i].code;
}
}
const declFileCompilationResult =
Harness.Compiler.compileDeclarationFiles(
toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined);
if (declFileCompilationResult && declFileCompilationResult.declResult.errors.length) {
jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n";
jsCode += "\r\n\r\n";
jsCode += Harness.Compiler.getErrorBaseline(declFileCompilationResult.declInputFiles.concat(declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors);
}
if (jsCode.length > 0) {
return tsCode + "\r\n\r\n" + jsCode;
}
else {
/* tslint:disable:no-null-keyword */
return null;
/* tslint:enable:no-null-keyword */
}
});
}
export function collateOutputs(outputFiles: Harness.Compiler.GeneratedFile[]): string {
// Collect, test, and sort the fileNames
outputFiles.sort((a, b) => cleanName(a.fileName).localeCompare(cleanName(b.fileName)));
@@ -1558,7 +1785,7 @@ namespace Harness {
tsConfig.options.configFilePath = data.name;
// delete entry from the list
testUnitData.splice(i, 1);
ts.orderedRemoveItemAt(testUnitData, i);
break;
}
@@ -1604,31 +1831,7 @@ namespace Harness {
}
const fileCache: { [idx: string]: boolean } = {};
function generateActual(actualFileName: string, generateContent: () => string): string {
// For now this is written using TypeScript, because sys is not available when running old test cases.
// But we need to move to sys once we have
// Creates the directory including its parent if not already present
function createDirectoryStructure(dirName: string) {
if (fileCache[dirName] || IO.directoryExists(dirName)) {
fileCache[dirName] = true;
return;
}
const parentDirectory = IO.directoryName(dirName);
if (parentDirectory != "") {
createDirectoryStructure(parentDirectory);
}
IO.createDirectory(dirName);
fileCache[dirName] = true;
}
// Create folders if needed
createDirectoryStructure(Harness.IO.directoryName(actualFileName));
// Delete the actual file in case it fails
if (IO.fileExists(actualFileName)) {
IO.deleteFile(actualFileName);
}
function generateActual(generateContent: () => string): string {
const actual = generateContent();
@@ -1663,43 +1866,51 @@ namespace Harness {
return { expected, actual };
}
function writeComparison(expected: string, actual: string, relativeFileName: string, actualFileName: string, descriptionForDescribe: string) {
function writeComparison(expected: string, actual: string, relativeFileName: string, actualFileName: string) {
// For now this is written using TypeScript, because sys is not available when running old test cases.
// But we need to move to sys once we have
// Creates the directory including its parent if not already present
function createDirectoryStructure(dirName: string) {
if (fileCache[dirName] || IO.directoryExists(dirName)) {
fileCache[dirName] = true;
return;
}
const parentDirectory = IO.directoryName(dirName);
if (parentDirectory != "") {
createDirectoryStructure(parentDirectory);
}
IO.createDirectory(dirName);
fileCache[dirName] = true;
}
// Create folders if needed
createDirectoryStructure(Harness.IO.directoryName(actualFileName));
// Delete the actual file in case it fails
if (IO.fileExists(actualFileName)) {
IO.deleteFile(actualFileName);
}
const encoded_actual = Utils.encodeString(actual);
if (expected !== encoded_actual) {
if (actual === NoContent) {
IO.writeFile(localPath(relativeFileName + ".delete"), "");
IO.writeFile(actualFileName + ".delete", "");
}
else {
IO.writeFile(localPath(relativeFileName), actual);
IO.writeFile(actualFileName, actual);
}
// Overwrite & issue error
const errMsg = "The baseline file " + relativeFileName + " has changed.";
throw new Error(errMsg);
throw new Error(`The baseline file ${relativeFileName} has changed.`);
}
}
export function runBaseline(relativeFileName: string, generateContent: () => string, opts?: BaselineOptions): void {
export function runBaseline(
descriptionForDescribe: string,
relativeFileName: string,
generateContent: () => string,
runImmediately = false,
opts?: BaselineOptions): void {
let actual = <string>undefined;
const actualFileName = localPath(relativeFileName, opts && opts.Baselinefolder, opts && opts.Subfolder);
if (runImmediately) {
actual = generateActual(actualFileName, generateContent);
const comparison = compareToBaseline(actual, relativeFileName, opts);
writeComparison(comparison.expected, comparison.actual, relativeFileName, actualFileName, descriptionForDescribe);
}
else {
actual = generateActual(actualFileName, generateContent);
const comparison = compareToBaseline(actual, relativeFileName, opts);
writeComparison(comparison.expected, comparison.actual, relativeFileName, actualFileName, descriptionForDescribe);
}
const actual = generateActual(generateContent);
const comparison = compareToBaseline(actual, relativeFileName, opts);
writeComparison(comparison.expected, comparison.actual, relativeFileName, actualFileName);
}
}
+5 -5
View File
@@ -459,7 +459,7 @@ class ProjectRunner extends RunnerBase {
});
it("Resolution information of (" + moduleNameToString(moduleKind) + "): " + testCaseFileName, () => {
Harness.Baseline.runBaseline("Resolution information of (" + moduleNameToString(compilerResult.moduleKind) + "): " + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + ".json", () => {
Harness.Baseline.runBaseline(getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + ".json", () => {
return JSON.stringify(getCompilerResolutionInfo(), undefined, " ");
});
});
@@ -467,7 +467,7 @@ class ProjectRunner extends RunnerBase {
it("Errors for (" + moduleNameToString(moduleKind) + "): " + testCaseFileName, () => {
if (compilerResult.errors.length) {
Harness.Baseline.runBaseline("Errors for (" + moduleNameToString(compilerResult.moduleKind) + "): " + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + ".errors.txt", () => {
Harness.Baseline.runBaseline(getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + ".errors.txt", () => {
return getErrorsBaseline(compilerResult);
});
}
@@ -481,7 +481,7 @@ class ProjectRunner extends RunnerBase {
// There may be multiple files with different baselines. Run all and report at the end, else
// it stops copying the remaining emitted files from 'local/projectOutput' to 'local/project'.
try {
Harness.Baseline.runBaseline("Baseline of emitted result (" + moduleNameToString(compilerResult.moduleKind) + "): " + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + outputFile.fileName, () => {
Harness.Baseline.runBaseline(getBaselineFolder(compilerResult.moduleKind) + outputFile.fileName, () => {
try {
return Harness.IO.readFile(getProjectOutputFolder(outputFile.fileName, compilerResult.moduleKind));
}
@@ -503,7 +503,7 @@ class ProjectRunner extends RunnerBase {
it("SourceMapRecord for (" + moduleNameToString(moduleKind) + "): " + testCaseFileName, () => {
if (compilerResult.sourceMapData) {
Harness.Baseline.runBaseline("SourceMapRecord for (" + moduleNameToString(compilerResult.moduleKind) + "): " + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + ".sourcemap.txt", () => {
Harness.Baseline.runBaseline(getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + ".sourcemap.txt", () => {
return Harness.SourceMapRecorder.getSourceMapRecord(compilerResult.sourceMapData, compilerResult.program,
ts.filter(compilerResult.outputFiles, outputFile => Harness.Compiler.isJS(outputFile.emittedFileName)));
});
@@ -516,7 +516,7 @@ class ProjectRunner extends RunnerBase {
if (!compilerResult.errors.length && testCase.declaration) {
const dTsCompileResult = compileCompileDTsFiles(compilerResult);
if (dTsCompileResult && dTsCompileResult.errors.length) {
Harness.Baseline.runBaseline("Errors in generated Dts files for (" + moduleNameToString(compilerResult.moduleKind) + "): " + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + ".dts.errors.txt", () => {
Harness.Baseline.runBaseline(getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + ".dts.errors.txt", () => {
return getErrorsBaseline(dTsCompileResult);
});
}
+19 -13
View File
@@ -158,41 +158,41 @@ namespace RWC {
it("has the expected emitted code", () => {
Harness.Baseline.runBaseline("has the expected emitted code", baseName + ".output.js", () => {
Harness.Baseline.runBaseline(`${baseName}.output.js`, () => {
return Harness.Compiler.collateOutputs(compilerResult.files);
}, false, baselineOpts);
}, baselineOpts);
});
it("has the expected declaration file content", () => {
Harness.Baseline.runBaseline("has the expected declaration file content", baseName + ".d.ts", () => {
Harness.Baseline.runBaseline(`${baseName}.d.ts`, () => {
if (!compilerResult.declFilesCode.length) {
return null;
}
return Harness.Compiler.collateOutputs(compilerResult.declFilesCode);
}, false, baselineOpts);
}, baselineOpts);
});
it("has the expected source maps", () => {
Harness.Baseline.runBaseline("has the expected source maps", baseName + ".map", () => {
Harness.Baseline.runBaseline(`${baseName}.map`, () => {
if (!compilerResult.sourceMaps.length) {
return null;
}
return Harness.Compiler.collateOutputs(compilerResult.sourceMaps);
}, false, baselineOpts);
}, baselineOpts);
});
/*it("has correct source map record", () => {
if (compilerOptions.sourceMap) {
Harness.Baseline.runBaseline("has correct source map record", baseName + ".sourcemap.txt", () => {
Harness.Baseline.runBaseline(baseName + ".sourcemap.txt", () => {
return compilerResult.getSourceMapRecord();
}, false, baselineOpts);
}, baselineOpts);
}
});*/
it("has the expected errors", () => {
Harness.Baseline.runBaseline("has the expected errors", baseName + ".errors.txt", () => {
Harness.Baseline.runBaseline(`${baseName}.errors.txt`, () => {
if (compilerResult.errors.length === 0) {
return null;
}
@@ -200,14 +200,14 @@ namespace RWC {
const baselineFiles = inputFiles.concat(otherFiles).filter(f => !Harness.isDefaultLibraryFile(f.unitName));
const errors = compilerResult.errors.filter(e => !Harness.isDefaultLibraryFile(e.file.fileName));
return Harness.Compiler.getErrorBaseline(baselineFiles, errors);
}, false, baselineOpts);
}, baselineOpts);
});
// Ideally, a generated declaration file will have no errors. But we allow generated
// declaration file errors as part of the baseline.
it("has the expected errors in generated declaration files", () => {
if (compilerOptions.declaration && !compilerResult.errors.length) {
Harness.Baseline.runBaseline("has the expected errors in generated declaration files", baseName + ".dts.errors.txt", () => {
Harness.Baseline.runBaseline(`${baseName}.dts.errors.txt`, () => {
const declFileCompilationResult = Harness.Compiler.compileDeclarationFiles(
inputFiles, otherFiles, compilerResult, /*harnessSettings*/ undefined, compilerOptions, currentDirectory);
@@ -218,11 +218,17 @@ namespace RWC {
return Harness.Compiler.minimalDiagnosticsToString(declFileCompilationResult.declResult.errors) +
Harness.IO.newLine() + Harness.IO.newLine() +
Harness.Compiler.getErrorBaseline(declFileCompilationResult.declInputFiles.concat(declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.errors);
}, false, baselineOpts);
}, baselineOpts);
}
});
// TODO: Type baselines (need to refactor out from compilerRunner)
it("has the expected types", () => {
// We don't need to pass the extension here because "doTypeAndSymbolBaseline" will append appropriate extension of ".types" or ".symbols"
Harness.Compiler.doTypeAndSymbolBaseline(baseName, compilerResult, inputFiles
.concat(otherFiles)
.filter(file => !!compilerResult.program.getSourceFile(file.unitName))
.filter(e => !Harness.isDefaultLibraryFile(e.unitName)), baselineOpts);
});
});
}
}
+6 -6
View File
@@ -67,21 +67,21 @@ class Test262BaselineRunner extends RunnerBase {
});
it("has the expected emitted code", () => {
Harness.Baseline.runBaseline("has the expected emitted code", testState.filename + ".output.js", () => {
Harness.Baseline.runBaseline(testState.filename + ".output.js", () => {
const files = testState.compilerResult.files.filter(f => f.fileName !== Test262BaselineRunner.helpersFilePath);
return Harness.Compiler.collateOutputs(files);
}, false, Test262BaselineRunner.baselineOptions);
}, Test262BaselineRunner.baselineOptions);
});
it("has the expected errors", () => {
Harness.Baseline.runBaseline("has the expected errors", testState.filename + ".errors.txt", () => {
Harness.Baseline.runBaseline(testState.filename + ".errors.txt", () => {
const errors = testState.compilerResult.errors;
if (errors.length === 0) {
return null;
}
return Harness.Compiler.getErrorBaseline(testState.inputFiles, errors);
}, false, Test262BaselineRunner.baselineOptions);
}, Test262BaselineRunner.baselineOptions);
});
it("satisfies invariants", () => {
@@ -90,10 +90,10 @@ class Test262BaselineRunner extends RunnerBase {
});
it("has the expected AST", () => {
Harness.Baseline.runBaseline("has the expected AST", testState.filename + ".AST.txt", () => {
Harness.Baseline.runBaseline(testState.filename + ".AST.txt", () => {
const sourceFile = testState.compilerResult.program.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename));
return Utils.sourceFileToJSON(sourceFile);
}, false, Test262BaselineRunner.baselineOptions);
}, Test262BaselineRunner.baselineOptions);
});
});
}
@@ -403,6 +403,7 @@ namespace ts {
{
compilerOptions: <CompilerOptions>{
allowJs: true,
maxNodeModuleJsDepth: 2,
module: ModuleKind.CommonJS,
target: ScriptTarget.ES5,
noImplicitAny: false,
@@ -429,6 +430,7 @@ namespace ts {
{
compilerOptions: <CompilerOptions>{
allowJs: false,
maxNodeModuleJsDepth: 2,
module: ModuleKind.CommonJS,
target: ScriptTarget.ES5,
noImplicitAny: false,
@@ -450,7 +452,8 @@ namespace ts {
{
compilerOptions:
{
allowJs: true
allowJs: true,
maxNodeModuleJsDepth: 2
},
errors: [{
file: undefined,
@@ -469,7 +472,8 @@ namespace ts {
{
compilerOptions:
{
allowJs: true
allowJs: true,
maxNodeModuleJsDepth: 2
},
errors: <Diagnostic[]>[]
}
+1 -1
View File
@@ -10,7 +10,7 @@ namespace ts {
const outputFileName = `tsConfig/${name.replace(/[^a-z0-9\-. ]/ig, "")}/tsconfig.json`;
it(`Correct output for ${outputFileName}`, () => {
Harness.Baseline.runBaseline("Correct output", outputFileName, () => {
Harness.Baseline.runBaseline(outputFileName, () => {
if (initResult) {
return JSON.stringify(initResult, undefined, 4);
}
+5 -19
View File
@@ -767,16 +767,9 @@ namespace ts {
parsesCorrectly(
"{null}",
`{
"kind": "JSDocTypeReference",
"kind": "NullKeyword",
"pos": 1,
"end": 5,
"name": {
"kind": "Identifier",
"pos": 1,
"end": 5,
"originalKeywordKind": "NullKeyword",
"text": "null"
}
"end": 5
}`);
});
@@ -784,16 +777,9 @@ namespace ts {
parsesCorrectly(
"{undefined}",
`{
"kind": "JSDocTypeReference",
"kind": "UndefinedKeyword",
"pos": 1,
"end": 10,
"name": {
"kind": "Identifier",
"pos": 1,
"end": 10,
"originalKeywordKind": "UndefinedKeyword",
"text": "undefined"
}
"end": 10
}`);
});
@@ -2379,4 +2365,4 @@ namespace ts {
});
});
});
}
}
@@ -1,79 +0,0 @@
class a {
constructor ( n : number ) ;
constructor ( s : string ) ;
constructor ( ns : any ) {
}
public pgF ( ) { } ;
public pv ;
public get d ( ) {
return 30 ;
}
public set d ( ) {
}
public static get p2 ( ) {
return { x : 30 , y : 40 } ;
}
private static d2 ( ) {
}
private static get p3 ( ) {
return "string" ;
}
private pv3 ;
private foo ( n : number ) : string ;
private foo ( s : string ) : string ;
private foo ( ns : any ) {
return ns.toString ( ) ;
}
}
class b extends a {
}
class m1b {
}
interface m1ib {
}
class c extends m1b {
}
class ib2 implements m1ib {
}
declare class aAmbient {
constructor ( n : number ) ;
constructor ( s : string ) ;
public pgF ( ) : void ;
public pv ;
public d : number ;
static p2 : { x : number ; y : number ; } ;
static d2 ( ) ;
static p3 ;
private pv3 ;
private foo ( s ) ;
}
class d {
private foo ( n : number ) : string ;
private foo ( ns : any ) {
return ns.toString ( ) ;
}
private foo ( s : string ) : string ;
}
class e {
private foo ( ns : any ) {
return ns.toString ( ) ;
}
private foo ( s : string ) : string ;
private foo ( n : number ) : string ;
}
@@ -1,79 +0,0 @@
class a {
constructor(n: number);
constructor(s: string);
constructor(ns: any) {
}
public pgF() { };
public pv;
public get d() {
return 30;
}
public set d() {
}
public static get p2() {
return { x: 30, y: 40 };
}
private static d2() {
}
private static get p3() {
return "string";
}
private pv3;
private foo(n: number): string;
private foo(s: string): string;
private foo(ns: any) {
return ns.toString();
}
}
class b extends a {
}
class m1b {
}
interface m1ib {
}
class c extends m1b {
}
class ib2 implements m1ib {
}
declare class aAmbient {
constructor(n: number);
constructor(s: string);
public pgF(): void;
public pv;
public d: number;
static p2: { x: number; y: number; };
static d2();
static p3;
private pv3;
private foo(s);
}
class d {
private foo(n: number): string;
private foo(ns: any) {
return ns.toString();
}
private foo(s: string): string;
}
class e {
private foo(ns: any) {
return ns.toString();
}
private foo(s: string): string;
private foo(n: number): string;
}
@@ -1,4 +0,0 @@
class foo {
constructor (n?: number, m? = 5, o?: string = "") { }
x:number = 1?2:3;
}
@@ -1,4 +0,0 @@
class foo {
constructor(n?: number, m? = 5, o?: string = "") { }
x: number = 1 ? 2 : 3;
}
@@ -1,3 +0,0 @@
$ ( document ) . ready ( function ( ) {
alert ( 'i am ready' ) ;
} );
@@ -1,3 +0,0 @@
$(document).ready(function() {
alert('i am ready');
});
@@ -1,10 +0,0 @@
function foo ( x : { } ) { }
foo ( { } ) ;
interface bar {
x : { } ;
y : ( ) => { } ;
}
@@ -1,10 +0,0 @@
function foo(x: {}) { }
foo({});
interface bar {
x: {};
y: () => {};
}
@@ -1,112 +0,0 @@
// valid
( ) => 1 ;
( arg ) => 2 ;
arg => 2 ;
( arg = 1 ) => 3 ;
( arg ? ) => 4 ;
( arg : number ) => 5 ;
( arg : number = 0 ) => 6 ;
( arg ? : number ) => 7 ;
( ... arg : number [ ] ) => 8 ;
( arg1 , arg2 ) => 12 ;
( arg1 = 1 , arg2 =3 ) => 13 ;
( arg1 ? , arg2 ? ) => 14 ;
( arg1 : number , arg2 : number ) => 15 ;
( arg1 : number = 0 , arg2 : number = 1 ) => 16 ;
( arg1 ? : number , arg2 ? : number ) => 17 ;
( arg1 , ... arg2 : number [ ] ) => 18 ;
( arg1 , arg2 ? : number ) => 19 ;
// in paren
( ( ) => 21 ) ;
( ( arg ) => 22 ) ;
( ( arg = 1 ) => 23 ) ;
( ( arg ? ) => 24 ) ;
( ( arg : number ) => 25 ) ;
( ( arg : number = 0 ) => 26 ) ;
( ( arg ? : number ) => 27 ) ;
( ( ... arg : number [ ] ) => 28 ) ;
// in multiple paren
( ( ( ( ( arg ) => { return 32 ; } ) ) ) ) ;
// in ternary exression
false ? ( ) => 41 : null ;
false ? ( arg ) => 42 : null ;
false ? ( arg = 1 ) => 43 : null ;
false ? ( arg ? ) => 44 : null ;
false ? ( arg : number ) => 45 : null ;
false ? ( arg ? : number ) => 46 : null ;
false ? ( arg ? : number = 0 ) => 47 : null ;
false ? ( ... arg : number [ ] ) => 48 : null ;
// in ternary exression within paren
false ? ( ( ) => 51 ) : null ;
false ? ( ( arg ) => 52 ) : null ;
false ? ( ( arg = 1 ) => 53 ) : null ;
false ? ( ( arg ? ) => 54 ) : null ;
false ? ( ( arg : number ) => 55 ) : null ;
false ? ( ( arg ? : number ) => 56 ) : null ;
false ? ( ( arg ? : number = 0 ) => 57 ) : null ;
false ? ( ( ... arg : number [ ] ) => 58 ) : null ;
// ternary exression's else clause
false ? null : ( ) => 61 ;
false ? null : ( arg ) => 62 ;
false ? null : ( arg = 1 ) => 63 ;
false ? null : ( arg ? ) => 64 ;
false ? null : ( arg : number ) => 65 ;
false ? null : ( arg ? : number ) => 66 ;
false ? null : ( arg ? : number = 0 ) => 67 ;
false ? null : ( ... arg : number [ ] ) => 68 ;
// nested ternary expressions
( a ? ) => { return a ; } ? ( b ? ) => { return b ; } : ( c ? ) => { return c ; } ;
//multiple levels
( a ? ) => { return a ; } ? ( b ) => ( c ) => 81 : ( c ) => ( d ) => 82 ;
// In Expressions
( ( arg ) => 90 ) instanceof Function ;
( ( arg = 1 ) => 91 ) instanceof Function ;
( ( arg ? ) => 92 ) instanceof Function ;
( ( arg : number ) => 93 ) instanceof Function ;
( ( arg : number = 1 ) => 94 ) instanceof Function ;
( ( arg ? : number ) => 95 ) instanceof Function ;
( ( ... arg : number [ ] ) => 96 ) instanceof Function ;
'' + ( arg ) => 100 ;
( ( arg ) => 0 ) + '' + ( arg ) => 101 ;
( ( arg = 1 ) => 0 ) + '' + ( arg = 2 ) => 102 ;
( ( arg ? ) => 0 ) + '' + ( arg ? ) => 103 ;
( ( arg : number ) => 0 ) + '' + ( arg : number ) => 104 ;
( ( arg : number = 1 ) => 0 ) + '' + ( arg : number = 2 ) => 105 ;
( ( arg ? : number = 1 ) => 0 ) + '' + ( arg ? : number = 2 ) => 106 ;
( ( ... arg : number [ ] ) => 0 ) + '' + ( ... arg : number [ ] ) => 107 ;
( ( arg1 , arg2 ? ) => 0 ) + '' + ( arg1 , arg2 ? ) => 108 ;
( ( arg1 , ... arg2 : number [ ] ) => 0 ) + '' + ( arg1 , ... arg2 : number [ ] ) => 108 ;
// Function Parameters
function foo ( ... arg : any [ ] ) { }
foo (
( a ) => 110 ,
( ( a ) => 111 ) ,
( a ) => {
return 112 ;
} ,
( a ? ) => 113 ,
( a , b ? ) => 114 ,
( a : number ) => 115 ,
( a : number = 0 ) => 116 ,
( a = 0 ) => 117 ,
( a ? : number = 0 ) => 118 ,
( a ? , b ? : number = 0 ) => 118 ,
( ... a : number [ ] ) => 119 ,
( a , b ? = 0 , ... c : number [ ] ) => 120 ,
( a ) => ( b ) => ( c ) => 121 ,
false ? ( a ) => 0 : ( b ) => 122
) ;
@@ -1,112 +0,0 @@
// valid
() => 1;
(arg) => 2;
arg => 2;
(arg = 1) => 3;
(arg?) => 4;
(arg: number) => 5;
(arg: number = 0) => 6;
(arg?: number) => 7;
(...arg: number[]) => 8;
(arg1, arg2) => 12;
(arg1 = 1, arg2 = 3) => 13;
(arg1?, arg2?) => 14;
(arg1: number, arg2: number) => 15;
(arg1: number = 0, arg2: number = 1) => 16;
(arg1?: number, arg2?: number) => 17;
(arg1, ...arg2: number[]) => 18;
(arg1, arg2?: number) => 19;
// in paren
(() => 21);
((arg) => 22);
((arg = 1) => 23);
((arg?) => 24);
((arg: number) => 25);
((arg: number = 0) => 26);
((arg?: number) => 27);
((...arg: number[]) => 28);
// in multiple paren
(((((arg) => { return 32; }))));
// in ternary exression
false ? () => 41 : null;
false ? (arg) => 42 : null;
false ? (arg = 1) => 43 : null;
false ? (arg?) => 44 : null;
false ? (arg: number) => 45 : null;
false ? (arg?: number) => 46 : null;
false ? (arg?: number = 0) => 47 : null;
false ? (...arg: number[]) => 48 : null;
// in ternary exression within paren
false ? (() => 51) : null;
false ? ((arg) => 52) : null;
false ? ((arg = 1) => 53) : null;
false ? ((arg?) => 54) : null;
false ? ((arg: number) => 55) : null;
false ? ((arg?: number) => 56) : null;
false ? ((arg?: number = 0) => 57) : null;
false ? ((...arg: number[]) => 58) : null;
// ternary exression's else clause
false ? null : () => 61;
false ? null : (arg) => 62;
false ? null : (arg = 1) => 63;
false ? null : (arg?) => 64;
false ? null : (arg: number) => 65;
false ? null : (arg?: number) => 66;
false ? null : (arg?: number = 0) => 67;
false ? null : (...arg: number[]) => 68;
// nested ternary expressions
(a?) => { return a; } ? (b?) => { return b; } : (c?) => { return c; };
//multiple levels
(a?) => { return a; } ? (b) => (c) => 81 : (c) => (d) => 82;
// In Expressions
((arg) => 90) instanceof Function;
((arg = 1) => 91) instanceof Function;
((arg?) => 92) instanceof Function;
((arg: number) => 93) instanceof Function;
((arg: number = 1) => 94) instanceof Function;
((arg?: number) => 95) instanceof Function;
((...arg: number[]) => 96) instanceof Function;
'' + (arg) => 100;
((arg) => 0) + '' + (arg) => 101;
((arg = 1) => 0) + '' + (arg = 2) => 102;
((arg?) => 0) + '' + (arg?) => 103;
((arg: number) => 0) + '' + (arg: number) => 104;
((arg: number = 1) => 0) + '' + (arg: number = 2) => 105;
((arg?: number = 1) => 0) + '' + (arg?: number = 2) => 106;
((...arg: number[]) => 0) + '' + (...arg: number[]) => 107;
((arg1, arg2?) => 0) + '' + (arg1, arg2?) => 108;
((arg1, ...arg2: number[]) => 0) + '' + (arg1, ...arg2: number[]) => 108;
// Function Parameters
function foo(...arg: any[]) { }
foo(
(a) => 110,
((a) => 111),
(a) => {
return 112;
},
(a?) => 113,
(a, b?) => 114,
(a: number) => 115,
(a: number = 0) => 116,
(a = 0) => 117,
(a?: number = 0) => 118,
(a?, b?: number = 0) => 118,
(...a: number[]) => 119,
(a, b? = 0, ...c: number[]) => 120,
(a) => (b) => (c) => 121,
false ? (a) => 0 : (b) => 122
);
@@ -1,2 +0,0 @@
if(false){debugger;}
if ( false ) { debugger ; }
@@ -1,2 +0,0 @@
if (false) { debugger; }
if (false) { debugger; }
@@ -1,13 +0,0 @@
var fun1 = function ( ) {
var x = 'foo' ,
z = 'bar' ;
return x ;
},
fun2 = ( function ( f ) {
var fun = function ( ) {
console . log ( f ( ) ) ;
},
x = 'Foo' ;
return fun ;
} ( fun1 ) ) ;
@@ -1,13 +0,0 @@
var fun1 = function() {
var x = 'foo',
z = 'bar';
return x;
},
fun2 = (function(f) {
var fun = function() {
console.log(f());
},
x = 'Foo';
return fun;
} (fun1));
@@ -1,3 +0,0 @@
export class A {
}
@@ -1,6 +0,0 @@
module Foo {
}
import bar = Foo;
import bar2=Foo;
@@ -1,6 +0,0 @@
module Foo {
}
import bar = Foo;
import bar2 = Foo;
@@ -1,95 +0,0 @@
var a;var c , b;var $d
var $e
var f
a++;b++;
function f ( ) {
for (i = 0; i < 10; i++) {
k = abc + 123 ^ d;
a = XYZ[m (a[b[c][d]])];
break;
switch ( variable){
case 1: abc += 425;
break;
case 404 : a [x--/2]%=3 ;
break ;
case vari : v[--x ] *=++y*( m + n / k[z]);
for (a in b){
for (a = 0; a < 10; ++a) {
a++;--a;
if (a == b) {
a++;b--;
}
else
if (a == c){
++a;
(--c)+=d;
$c = $a + --$b;
}
if (a == b)
if (a != b) {
if (a !== b)
if (a === b)
--a;
else
--a;
else {
a--;++b;
a++
}
}
}
for (x in y) {
m-=m;
k=1+2+3+4;
}
}
break;
}
}
var a ={b:function(){}};
return {a:1,b:2}
}
var z = 1;
for (i = 0; i < 10; i++)
for (j = 0; j < 10; j++)
for (k = 0; k < 10; ++k) {
z++;
}
for (k = 0; k < 10; k += 2) {
z++;
}
$(document).ready ();
function pageLoad() {
$('#TextBox1' ) . unbind ( ) ;
$('#TextBox1' ) . datepicker ( ) ;
}
function pageLoad ( ) {
var webclass=[
{ 'student' :
{ 'id': '1', 'name': 'Linda Jones', 'legacySkill': 'Access, VB 5.0' }
} ,
{ 'student':
{'id':'2','name':'Adam Davidson','legacySkill':'Cobol,MainFrame'}
} ,
{ 'student':
{ 'id':'3','name':'Charles Boyer' ,'legacySkill':'HTML, XML'}
}
];
$create(Sys.UI.DataView,{data:webclass},null,null,$get('SList'));
}
$( document ).ready(function(){
alert('hello');
} ) ;
@@ -1,98 +0,0 @@
var a; var c, b; var $d
var $e
var f
a++; b++;
function f() {
for (i = 0; i < 10; i++) {
k = abc + 123 ^ d;
a = XYZ[m(a[b[c][d]])];
break;
switch (variable) {
case 1: abc += 425;
break;
case 404: a[x-- / 2] %= 3;
break;
case vari: v[--x] *= ++y * (m + n / k[z]);
for (a in b) {
for (a = 0; a < 10; ++a) {
a++; --a;
if (a == b) {
a++; b--;
}
else
if (a == c) {
++a;
(--c) += d;
$c = $a + --$b;
}
if (a == b)
if (a != b) {
if (a !== b)
if (a === b)
--a;
else
--a;
else {
a--; ++b;
a++
}
}
}
for (x in y) {
m -= m;
k = 1 + 2 + 3 + 4;
}
}
break;
}
}
var a = { b: function() { } };
return { a: 1, b: 2 }
}
var z = 1;
for (i = 0; i < 10; i++)
for (j = 0; j < 10; j++)
for (k = 0; k < 10; ++k) {
z++;
}
for (k = 0; k < 10; k += 2) {
z++;
}
$(document).ready();
function pageLoad() {
$('#TextBox1').unbind();
$('#TextBox1').datepicker();
}
function pageLoad() {
var webclass = [
{
'student':
{ 'id': '1', 'name': 'Linda Jones', 'legacySkill': 'Access, VB 5.0' }
},
{
'student':
{ 'id': '2', 'name': 'Adam Davidson', 'legacySkill': 'Cobol,MainFrame' }
},
{
'student':
{ 'id': '3', 'name': 'Charles Boyer', 'legacySkill': 'HTML, XML' }
}
];
$create(Sys.UI.DataView, { data: webclass }, null, null, $get('SList'));
}
$(document).ready(function() {
alert('hello');
});
@@ -1,3 +0,0 @@
module Foo {
export module A . B . C { }
}
@@ -1,3 +0,0 @@
module Foo {
export module A.B.C { }
}
@@ -1,76 +0,0 @@
module mod1 {
export class b {
}
class d {
}
export interface ib {
}
}
module m2 {
export module m3 {
export class c extends mod1.b {
}
export class ib2 implements mod1.ib {
}
}
}
class c extends mod1.b {
}
class ib2 implements mod1.ib {
}
declare export module "m4" {
export class d {
} ;
var x : d ;
export function foo ( ) : d ;
}
import m4 = module ( "m4" ) ;
export var x4 = m4.x ;
export var d4 = m4.d ;
export var f4 = m4.foo ( ) ;
export module m1 {
declare export module "m2" {
export class d {
} ;
var x: d ;
export function foo ( ) : d ;
}
import m2 = module ( "m2" ) ;
import m3 = module ( "m4" ) ;
export var x2 = m2.x ;
export var d2 = m2.d ;
export var f2 = m2.foo ( ) ;
export var x3 = m3.x ;
export var d3 = m3.d ;
export var f3 = m3.foo ( ) ;
}
export var x2 = m1.m2.x ;
export var d2 = m1.m2.d ;
export var f2 = m1.m2.foo ( ) ;
export var x3 = m1.m3.x ;
export var d3 = m1.m3.d ;
export var f3 = m1.m3.foo ( ) ;
export module m5 {
export var x2 = m1.m2.x ;
export var d2 = m1.m2.d ;
export var f2 = m1.m2.foo ( ) ;
export var x3 = m1.m3.x ;
export var d3 = m1.m3.d ;
export var f3 = m1.m3.foo ( ) ;
}
@@ -1,76 +0,0 @@
module mod1 {
export class b {
}
class d {
}
export interface ib {
}
}
module m2 {
export module m3 {
export class c extends mod1.b {
}
export class ib2 implements mod1.ib {
}
}
}
class c extends mod1.b {
}
class ib2 implements mod1.ib {
}
declare export module "m4" {
export class d {
};
var x: d;
export function foo(): d;
}
import m4 = module("m4");
export var x4 = m4.x;
export var d4 = m4.d;
export var f4 = m4.foo();
export module m1 {
declare export module "m2" {
export class d {
};
var x: d;
export function foo(): d;
}
import m2 = module("m2");
import m3 = module("m4");
export var x2 = m2.x;
export var d2 = m2.d;
export var f2 = m2.foo();
export var x3 = m3.x;
export var d3 = m3.d;
export var f3 = m3.foo();
}
export var x2 = m1.m2.x;
export var d2 = m1.m2.d;
export var f2 = m1.m2.foo();
export var x3 = m1.m3.x;
export var d3 = m1.m3.d;
export var f3 = m1.m3.foo();
export module m5 {
export var x2 = m1.m2.x;
export var d2 = m1.m2.d;
export var f2 = m1.m2.foo();
export var x3 = m1.m3.x;
export var d3 = m1.m3.d;
export var f3 = m1.m3.foo();
}
@@ -1,27 +0,0 @@
var x = {foo: 1,
bar: "tt",
boo: 1 + 5};
var x2 = {foo: 1,
bar: "tt",boo:1+5};
function Foo() {
var typeICalc = {
clear: {
"()": [1, 2, 3]
}
}
}
// Rule for object literal members for the "value" of the memebr to follow the indent
// of the member, i.e. the relative position of the value is maintained when the member
// is indented.
var x2 = {
foo:
3,
'bar':
{ a: 1, b : 2}
};
var x={ };
var y = {};
@@ -1,31 +0,0 @@
var x = {
foo: 1,
bar: "tt",
boo: 1 + 5
};
var x2 = {
foo: 1,
bar: "tt", boo: 1 + 5
};
function Foo() {
var typeICalc = {
clear: {
"()": [1, 2, 3]
}
}
}
// Rule for object literal members for the "value" of the memebr to follow the indent
// of the member, i.e. the relative position of the value is maintained when the member
// is indented.
var x2 = {
foo:
3,
'bar':
{ a: 1, b: 2 }
};
var x = {};
var y = {};
@@ -1,32 +0,0 @@
function f( ) {
var x = 3;
var z = 2 ;
a = z ++ - 2 * x ;
for ( ; ; ) {
a+=(g +g)*a%t;
b -- ;
}
switch ( a )
{
case 1 : {
a ++ ;
b--;
if(a===a)
return;
else
{
for(a in b)
if(a!=a)
{
for(a in b)
{
a++;
}
}
}
}
default:
break;
}
}
@@ -1,28 +0,0 @@
function f() {
var x = 3;
var z = 2;
a = z++ - 2 * x;
for (; ;) {
a += (g + g) * a % t;
b--;
}
switch (a) {
case 1: {
a++;
b--;
if (a === a)
return;
else {
for (a in b)
if (a != a) {
for (a in b) {
a++;
}
}
}
}
default:
break;
}
}
@@ -1 +0,0 @@
var a=b+c^d-e*++f;
@@ -1 +0,0 @@
var a = b + c ^ d - e * ++f;
@@ -1 +0,0 @@
class test { constructor () { } }
@@ -1 +0,0 @@
class test { constructor() { } }
@@ -1,10 +0,0 @@
module Tools {
export enum NodeType {
Error,
Comment,
}
export enum foob
{
Blah=1, Bleah=2
}
}
@@ -1,9 +0,0 @@
module Tools {
export enum NodeType {
Error,
Comment,
}
export enum foob {
Blah = 1, Bleah = 2
}
}
@@ -1,65 +0,0 @@
module MyModule
{
module A.B.C {
module F {
}
}
interface Blah
{
boo: string;
}
class Foo
{
}
class Foo2 {
public foo():number {
return 5 * 6;
}
public foo2() {
if (1 === 2)
{
var y : number= 76;
return y;
}
while (2 == 3) {
if ( y == null ) {
}
}
}
public foo3() {
if (1 === 2)
//comment preventing line merging
{
var y = 76;
return y;
}
}
}
}
function foo(a:number, b:number):number
{
return 0;
}
function bar(a:number, b:number) :number[] {
return [];
}
module BugFix3 {
declare var f: {
(): any;
(x: number): string;
foo: number;
};
}
@@ -1,58 +0,0 @@
module MyModule {
module A.B.C {
module F {
}
}
interface Blah {
boo: string;
}
class Foo {
}
class Foo2 {
public foo(): number {
return 5 * 6;
}
public foo2() {
if (1 === 2) {
var y: number = 76;
return y;
}
while (2 == 3) {
if (y == null) {
}
}
}
public foo3() {
if (1 === 2)
//comment preventing line merging
{
var y = 76;
return y;
}
}
}
}
function foo(a: number, b: number): number {
return 0;
}
function bar(a: number, b: number): number[] {
return [];
}
module BugFix3 {
declare var f: {
(): any;
(x: number): string;
foo: number;
};
}
@@ -1,17 +0,0 @@
function f(a,b,c,d){
for(var i=0;i<10;i++){
var a=0;
var b=a+a+a*a%a/2-1;
b+=a;
++b;
f(a,b,c,d);
if(1===1){
var m=function(e,f){
return e^f;
}
}
}
}
for (var i = 0 ; i < this.foo(); i++) {
}
@@ -1,17 +0,0 @@
function f(a, b, c, d) {
for (var i = 0; i < 10; i++) {
var a = 0;
var b = a + a + a * a % a / 2 - 1;
b += a;
++b;
f(a, b, c, d);
if (1 === 1) {
var m = function(e, f) {
return e ^ f;
}
}
}
}
for (var i = 0 ; i < this.foo(); i++) {
}
@@ -1,9 +0,0 @@
with (foo.bar)
{
}
with (bar.blah)
{
}
@@ -1,6 +0,0 @@
with (foo.bar) {
}
with (bar.blah) {
}
+4 -4
View File
@@ -62,7 +62,7 @@ namespace ts {
});
it("Correct errors for " + justName, () => {
Harness.Baseline.runBaseline("Correct errors", justName.replace(/\.tsx?$/, ".errors.txt"), () => {
Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".errors.txt"), () => {
if (transpileResult.diagnostics.length === 0) {
/* tslint:disable:no-null-keyword */
return null;
@@ -75,7 +75,7 @@ namespace ts {
if (canUseOldTranspile) {
it("Correct errors (old transpile) for " + justName, () => {
Harness.Baseline.runBaseline("Correct errors", justName.replace(/\.tsx?$/, ".oldTranspile.errors.txt"), () => {
Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".oldTranspile.errors.txt"), () => {
if (oldTranspileDiagnostics.length === 0) {
/* tslint:disable:no-null-keyword */
return null;
@@ -88,7 +88,7 @@ namespace ts {
}
it("Correct output for " + justName, () => {
Harness.Baseline.runBaseline("Correct output", justName.replace(/\.tsx?$/, ".js"), () => {
Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".js"), () => {
if (transpileResult.outputText) {
return transpileResult.outputText;
}
@@ -104,7 +104,7 @@ namespace ts {
if (canUseOldTranspile) {
it("Correct output (old transpile) for " + justName, () => {
Harness.Baseline.runBaseline("Correct output", justName.replace(/\.tsx?$/, ".oldTranspile.js"), () => {
Harness.Baseline.runBaseline(justName.replace(/\.tsx?$/, ".oldTranspile.js"), () => {
return oldTranspileResult;
});
});
+21
View File
@@ -181,5 +181,26 @@ namespace ts {
["/d.ts", "/folder/e.ts"]
);
});
it("parse and re-emit tsconfig.json file with diagnostics", () => {
const content = `{
"compilerOptions": {
"allowJs": true
// Some comments
"outDir": "bin"
}
"files": ["file1.ts"]
}`;
const { configJsonObject, diagnostics } = parseAndReEmitConfigJSONFile(content);
const expectedResult = {
compilerOptions: {
allowJs: true,
outDir: "bin"
},
files: ["file1.ts"]
};
assert.isTrue(diagnostics.length === 2);
assert.equal(JSON.stringify(configJsonObject), JSON.stringify(expectedResult));
});
});
}
+23 -10
View File
@@ -198,17 +198,13 @@ namespace ts {
watchDirectory(directoryName: string, callback: DirectoryWatcherCallback, recursive: boolean): DirectoryWatcher {
const path = this.toPath(directoryName);
const callbacks = multiMapAdd(this.watchedDirectories, path, { cb: callback, recursive });
const cbWithRecursive = { cb: callback, recursive };
const callbacks = multiMapAdd(this.watchedDirectories, path, cbWithRecursive);
return {
referenceCount: 0,
directoryName,
close: () => {
for (let i = 0; i < callbacks.length; i++) {
if (callbacks[i].cb === callback) {
callbacks.splice(i, 1);
break;
}
}
unorderedRemoveItem(callbacks, cbWithRecursive);
if (!callbacks.length) {
delete this.watchedDirectories[path];
}
@@ -241,8 +237,7 @@ namespace ts {
const callbacks = multiMapAdd(this.watchedFiles, path, callback);
return {
close: () => {
const i = callbacks.indexOf(callback);
callbacks.splice(i, 1);
unorderedRemoveItem(callbacks, callback);
if (!callbacks.length) {
delete this.watchedFiles[path];
}
@@ -257,7 +252,7 @@ namespace ts {
};
readonly clearTimeout = (timeoutId: any): void => {
if (typeof timeoutId === "number") {
this.callbackQueue.splice(timeoutId, 1);
orderedRemoveItemAt(this.callbackQueue, timeoutId);
}
};
@@ -621,5 +616,23 @@ namespace ts {
checkNumberOfConfiguredProjects(projectService, 1);
checkNumberOfInferredProjects(projectService, 0);
});
it("should tolerate config file errors and still try to build a project", () => {
const configFile: FileOrFolder = {
path: "/a/b/tsconfig.json",
content: `{
"compilerOptions": {
"target": "es6",
"allowAnything": true
},
"someOtherProperty": {}
}`
};
const host = new TestServerHost(/*useCaseSensitiveFileNames*/ false, getExecutingFilePathFromLibFile(libFile), "/", [commonFile1, commonFile2, libFile, configFile]);
const projectService = new server.ProjectService(host, nullLogger);
projectService.openClientFile(commonFile1.path);
checkNumberOfConfiguredProjects(projectService, 1);
checkConfiguredProjectRootFiles(projectService.configuredProjects[0], [commonFile1.path, commonFile2.path]);
});
});
}
+55 -15
View File
@@ -126,6 +126,7 @@ interface KeyAlgorithm {
}
interface KeyboardEventInit extends EventModifierInit {
code?: string;
key?: string;
location?: number;
repeat?: boolean;
@@ -2288,7 +2289,7 @@ declare var DeviceRotationRate: {
new(): DeviceRotationRate;
}
interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEvent {
interface Document extends Node, GlobalEventHandlers, NodeSelector, DocumentEvent, ParentNode {
/**
* Sets or gets the URL for the current document.
*/
@@ -3351,7 +3352,7 @@ declare var Document: {
new(): Document;
}
interface DocumentFragment extends Node, NodeSelector {
interface DocumentFragment extends Node, NodeSelector, ParentNode {
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}
@@ -3420,7 +3421,7 @@ declare var EXT_texture_filter_anisotropic: {
readonly TEXTURE_MAX_ANISOTROPY_EXT: number;
}
interface Element extends Node, GlobalEventHandlers, ElementTraversal, NodeSelector, ChildNode {
interface Element extends Node, GlobalEventHandlers, ElementTraversal, NodeSelector, ChildNode, ParentNode {
readonly classList: DOMTokenList;
className: string;
readonly clientHeight: number;
@@ -3675,6 +3676,16 @@ interface Element extends Node, GlobalEventHandlers, ElementTraversal, NodeSelec
getElementsByClassName(classNames: string): NodeListOf<Element>;
matches(selector: string): boolean;
closest(selector: string): Element | null;
scrollIntoView(arg?: boolean | ScrollIntoViewOptions): void;
scroll(options?: ScrollToOptions): void;
scroll(x: number, y: number): void;
scrollTo(options?: ScrollToOptions): void;
scrollTo(x: number, y: number): void;
scrollBy(options?: ScrollToOptions): void;
scrollBy(x: number, y: number): void;
insertAdjacentElement(position: string, insertedElement: Element): Element | null;
insertAdjacentHTML(where: string, html: string): void;
insertAdjacentText(where: string, text: string): void;
addEventListener(type: "MSGestureChange", listener: (this: this, ev: MSGestureEvent) => any, useCapture?: boolean): void;
addEventListener(type: "MSGestureDoubleTap", listener: (this: this, ev: MSGestureEvent) => any, useCapture?: boolean): void;
addEventListener(type: "MSGestureEnd", listener: (this: this, ev: MSGestureEvent) => any, useCapture?: boolean): void;
@@ -4446,7 +4457,7 @@ interface HTMLCanvasElement extends HTMLElement {
* @param type The standard MIME type for the image format to return. If you do not specify this parameter, the default value is a PNG format image.
*/
toDataURL(type?: string, ...args: any[]): string;
toBlob(callback: (result: Blob | null) => void, ... arguments: any[]): void;
toBlob(callback: (result: Blob | null) => void, type?: string, ...arguments: any[]): void;
}
declare var HTMLCanvasElement: {
@@ -4621,11 +4632,7 @@ interface HTMLElement extends Element {
click(): void;
dragDrop(): boolean;
focus(): void;
insertAdjacentElement(position: string, insertedElement: Element): Element;
insertAdjacentHTML(where: string, html: string): void;
insertAdjacentText(where: string, text: string): void;
msGetInputContext(): MSInputMethodContext;
scrollIntoView(top?: boolean): void;
setActive(): void;
addEventListener(type: "MSContentZoom", listener: (this: this, ev: UIEvent) => any, useCapture?: boolean): void;
addEventListener(type: "MSGestureChange", listener: (this: this, ev: MSGestureEvent) => any, useCapture?: boolean): void;
@@ -5890,6 +5897,7 @@ interface HTMLLinkElement extends HTMLElement, LinkStyle {
*/
type: string;
import?: Document;
integrity: string;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}
@@ -6178,7 +6186,7 @@ interface HTMLMediaElement extends HTMLElement {
*/
canPlayType(type: string): string;
/**
* Fires immediately after the client loads the object.
* Resets the audio or video object and loads a new media resource.
*/
load(): void;
/**
@@ -6751,6 +6759,7 @@ interface HTMLScriptElement extends HTMLElement {
* Sets or retrieves the MIME type for the associated scripting engine.
*/
type: string;
integrity: string;
}
declare var HTMLScriptElement: {
@@ -7756,6 +7765,7 @@ interface KeyboardEvent extends UIEvent {
readonly repeat: boolean;
readonly shiftKey: boolean;
readonly which: number;
readonly code: string;
getModifierState(keyArg: string): boolean;
initKeyboardEvent(typeArg: string, canBubbleArg: boolean, cancelableArg: boolean, viewArg: Window, keyArg: string, locationArg: number, modifiersListArg: string, repeat: boolean, locale: string): void;
readonly DOM_KEY_LOCATION_JOYSTICK: number;
@@ -9128,6 +9138,7 @@ interface PerformanceTiming {
readonly responseStart: number;
readonly unloadEventEnd: number;
readonly unloadEventStart: number;
readonly secureConnectionStart: number;
toJSON(): any;
}
@@ -11405,8 +11416,8 @@ declare var StereoPannerNode: {
interface Storage {
readonly length: number;
clear(): void;
getItem(key: string): string;
key(index: number): string;
getItem(key: string): string | null;
key(index: number): string | null;
removeItem(key: string): void;
setItem(key: string, data: string): void;
[key: string]: any;
@@ -12947,7 +12958,7 @@ interface Window extends EventTarget, WindowTimers, WindowSessionStorage, Window
onunload: (this: this, ev: Event) => any;
onvolumechange: (this: this, ev: Event) => any;
onwaiting: (this: this, ev: Event) => any;
readonly opener: Window;
opener: any;
orientation: string | number;
readonly outerHeight: number;
readonly outerWidth: number;
@@ -13002,6 +13013,9 @@ interface Window extends EventTarget, WindowTimers, WindowSessionStorage, Window
webkitConvertPointFromNodeToPage(node: Node, pt: WebKitPoint): WebKitPoint;
webkitConvertPointFromPageToNode(node: Node, pt: WebKitPoint): WebKitPoint;
webkitRequestAnimationFrame(callback: FrameRequestCallback): number;
scroll(options?: ScrollToOptions): void;
scrollTo(options?: ScrollToOptions): void;
scrollBy(options?: ScrollToOptions): void;
addEventListener(type: "MSGestureChange", listener: (this: this, ev: MSGestureEvent) => any, useCapture?: boolean): void;
addEventListener(type: "MSGestureDoubleTap", listener: (this: this, ev: MSGestureEvent) => any, useCapture?: boolean): void;
addEventListener(type: "MSGestureEnd", listener: (this: this, ev: MSGestureEvent) => any, useCapture?: boolean): void;
@@ -14029,6 +14043,20 @@ interface ProgressEventInit extends EventInit {
total?: number;
}
interface ScrollOptions {
behavior?: ScrollBehavior;
}
interface ScrollToOptions extends ScrollOptions {
left?: number;
top?: number;
}
interface ScrollIntoViewOptions extends ScrollOptions {
block?: ScrollLogicalPosition;
inline?: ScrollLogicalPosition;
}
interface ClipboardEventInit extends EventInit {
data?: string;
dataType?: string;
@@ -14072,7 +14100,7 @@ interface EcdsaParams extends Algorithm {
}
interface EcKeyGenParams extends Algorithm {
typedCurve: string;
namedCurve: string;
}
interface EcKeyAlgorithm extends KeyAlgorithm {
@@ -14208,6 +14236,13 @@ interface JsonWebKey {
k?: string;
}
interface ParentNode {
readonly children: HTMLCollection;
readonly firstElementChild: Element;
readonly lastElementChild: Element;
readonly childElementCount: number;
}
declare type EventListenerOrEventListenerObject = EventListener | EventListenerObject;
interface ErrorEventHandler {
@@ -14278,7 +14313,7 @@ declare var location: Location;
declare var locationbar: BarProp;
declare var menubar: BarProp;
declare var msCredentials: MSCredentials;
declare var name: string;
declare const name: never;
declare var navigator: Navigator;
declare var offscreenBuffering: string | boolean;
declare var onabort: (this: Window, ev: UIEvent) => any;
@@ -14372,7 +14407,7 @@ declare var ontouchstart: (ev: TouchEvent) => any;
declare var onunload: (this: Window, ev: Event) => any;
declare var onvolumechange: (this: Window, ev: Event) => any;
declare var onwaiting: (this: Window, ev: Event) => any;
declare var opener: Window;
declare var opener: any;
declare var orientation: string | number;
declare var outerHeight: number;
declare var outerWidth: number;
@@ -14425,6 +14460,9 @@ declare function webkitCancelAnimationFrame(handle: number): void;
declare function webkitConvertPointFromNodeToPage(node: Node, pt: WebKitPoint): WebKitPoint;
declare function webkitConvertPointFromPageToNode(node: Node, pt: WebKitPoint): WebKitPoint;
declare function webkitRequestAnimationFrame(callback: FrameRequestCallback): number;
declare function scroll(options?: ScrollToOptions): void;
declare function scrollTo(options?: ScrollToOptions): void;
declare function scrollBy(options?: ScrollToOptions): void;
declare function toString(): string;
declare function addEventListener(type: string, listener?: EventListenerOrEventListenerObject, useCapture?: boolean): void;
declare function dispatchEvent(evt: Event): boolean;
@@ -14580,6 +14618,8 @@ type MSOutboundPayload = MSVideoSendPayload | MSAudioSendPayload;
type RTCIceGatherCandidate = RTCIceCandidate | RTCIceCandidateComplete;
type RTCTransport = RTCDtlsTransport | RTCSrtpSdesTransport;
type payloadtype = number;
type ScrollBehavior = "auto" | "instant" | "smooth";
type ScrollLogicalPosition = "start" | "center" | "end" | "nearest";
type IDBValidKey = number | string | Date | IDBArrayKey;
type BufferSource = ArrayBuffer | ArrayBufferView;
type MouseWheelEvent = WheelEvent;
+1 -1
View File
@@ -1000,7 +1000,7 @@ interface EcdsaParams extends Algorithm {
}
interface EcKeyGenParams extends Algorithm {
typedCurve: string;
namedCurve: string;
}
interface EcKeyAlgorithm extends KeyAlgorithm {
+115 -106
View File
@@ -275,7 +275,7 @@ namespace ts.server {
removeRoot(info: ScriptInfo) {
if (this.filenameToScript.contains(info.path)) {
this.filenameToScript.remove(info.path);
this.roots = copyListRemovingItem(info, this.roots);
unorderedRemoveItem(this.roots, info);
this.resolvedModuleNames.remove(info.path);
this.resolvedTypeReferenceDirectives.remove(info.path);
}
@@ -585,16 +585,6 @@ namespace ts.server {
project?: Project;
}
function copyListRemovingItem<T>(item: T, list: T[]) {
const copiedList: T[] = [];
for (let i = 0, len = list.length; i < len; i++) {
if (list[i] != item) {
copiedList.push(list[i]);
}
}
return copiedList;
}
/**
* This helper funciton processes a list of projects and return the concatenated, sortd and deduplicated output of processing each project.
*/
@@ -603,8 +593,11 @@ namespace ts.server {
return projects.length > 1 ? deduplicate(result, areEqual) : result;
}
export type ProjectServiceEvent =
{ eventName: "context", data: { project: Project, fileName: string } } | { eventName: "configFileDiag", data: { triggerFile?: string, configFileName: string, diagnostics: Diagnostic[] } }
export interface ProjectServiceEventHandler {
(eventName: string, project: Project, fileName: string): void;
(event: ProjectServiceEvent): void;
}
export interface HostConfiguration {
@@ -699,7 +692,8 @@ namespace ts.server {
}
handleProjectFileListChanges(project: Project) {
const { projectOptions } = this.configFileToProjectOptions(project.projectFilename);
const { projectOptions, errors } = this.configFileToProjectOptions(project.projectFilename);
this.reportConfigFileDiagnostics(project.projectFilename, errors);
const newRootFiles = projectOptions.files.map((f => this.getCanonicalFileName(f)));
const currentRootFiles = project.getRootFiles().map((f => this.getCanonicalFileName(f)));
@@ -717,18 +711,32 @@ namespace ts.server {
}
}
reportConfigFileDiagnostics(configFileName: string, diagnostics: Diagnostic[], triggerFile?: string) {
if (diagnostics && diagnostics.length > 0) {
this.eventHandler({
eventName: "configFileDiag",
data: { configFileName, diagnostics, triggerFile }
});
}
}
/**
* This is the callback function when a watched directory has an added tsconfig file.
*/
directoryWatchedForTsconfigChanged(fileName: string) {
if (ts.getBaseFileName(fileName) != "tsconfig.json") {
if (ts.getBaseFileName(fileName) !== "tsconfig.json") {
this.log(fileName + " is not tsconfig.json");
return;
}
this.log("Detected newly added tsconfig file: " + fileName);
const { projectOptions } = this.configFileToProjectOptions(fileName);
const { projectOptions, errors } = this.configFileToProjectOptions(fileName);
this.reportConfigFileDiagnostics(fileName, errors);
if (!projectOptions) {
return;
}
const rootFilesInTsconfig = projectOptions.files.map(f => this.getCanonicalFileName(f));
const openFileRoots = this.openFileRoots.map(s => this.getCanonicalFileName(s.fileName));
@@ -748,10 +756,13 @@ namespace ts.server {
return ts.normalizePath(name);
}
watchedProjectConfigFileChanged(project: Project) {
watchedProjectConfigFileChanged(project: Project): void {
this.log("Config file changed: " + project.projectFilename);
this.updateConfiguredProject(project);
const configFileErrors = this.updateConfiguredProject(project);
this.updateProjectStructure();
if (configFileErrors && configFileErrors.length > 0) {
this.eventHandler({ eventName: "configFileDiag", data: { triggerFile: project.projectFilename, configFileName: project.projectFilename, diagnostics: configFileErrors } });
}
}
log(msg: string, type = "Err") {
@@ -828,13 +839,13 @@ namespace ts.server {
for (let j = 0, flen = this.openFileRoots.length; j < flen; j++) {
const openFile = this.openFileRoots[j];
if (this.eventHandler) {
this.eventHandler("context", openFile.defaultProject, openFile.fileName);
this.eventHandler({ eventName: "context", data: { project: openFile.defaultProject, fileName: openFile.fileName } });
}
}
for (let j = 0, flen = this.openFilesReferenced.length; j < flen; j++) {
const openFile = this.openFilesReferenced[j];
if (this.eventHandler) {
this.eventHandler("context", openFile.defaultProject, openFile.fileName);
this.eventHandler({ eventName: "context", data: { project: openFile.defaultProject, fileName: openFile.fileName } });
}
}
}
@@ -859,7 +870,7 @@ namespace ts.server {
project.directoryWatcher.close();
forEachProperty(project.directoriesWatchedForWildcards, watcher => { watcher.close(); });
delete project.directoriesWatchedForWildcards;
this.configuredProjects = copyListRemovingItem(project, this.configuredProjects);
unorderedRemoveItem(this.configuredProjects, project);
}
else {
for (const directory of project.directoriesWatchedForTsconfig) {
@@ -871,7 +882,7 @@ namespace ts.server {
delete project.projectService.directoryWatchersForTsconfig[directory];
}
}
this.inferredProjects = copyListRemovingItem(project, this.inferredProjects);
unorderedRemoveItem(this.inferredProjects, project);
}
const fileNames = project.getFileNames();
@@ -996,7 +1007,7 @@ namespace ts.server {
}
}
else {
this.openFilesReferenced = copyListRemovingItem(info, this.openFilesReferenced);
unorderedRemoveItem(this.openFilesReferenced, info);
}
info.close();
}
@@ -1218,7 +1229,7 @@ namespace ts.server {
const project = this.findConfiguredProjectByConfigFile(configFileName);
if (!project) {
const configResult = this.openConfigFile(configFileName, fileName);
if (!configResult.success) {
if (!configResult.project) {
return { configFileName, configFileErrors: configResult.errors };
}
else {
@@ -1234,11 +1245,12 @@ namespace ts.server {
else {
this.updateConfiguredProject(project);
}
return { configFileName };
}
else {
this.log("No config files found.");
}
return configFileName ? { configFileName } : {};
return {};
}
/**
@@ -1328,34 +1340,31 @@ namespace ts.server {
return undefined;
}
configFileToProjectOptions(configFilename: string): { succeeded: boolean, projectOptions?: ProjectOptions, errors?: Diagnostic[] } {
configFileToProjectOptions(configFilename: string): { projectOptions?: ProjectOptions, errors: Diagnostic[] } {
configFilename = ts.normalizePath(configFilename);
let errors: Diagnostic[] = [];
// file references will be relative to dirPath (or absolute)
const dirPath = ts.getDirectoryPath(configFilename);
const contents = this.host.readFile(configFilename);
const rawConfig: { config?: ProjectOptions; error?: Diagnostic; } = ts.parseConfigFileTextToJson(configFilename, contents);
if (rawConfig.error) {
return { succeeded: false, errors: [rawConfig.error] };
const { configJsonObject, diagnostics } = ts.parseAndReEmitConfigJSONFile(contents);
errors = concatenate(errors, diagnostics);
const parsedCommandLine = ts.parseJsonConfigFileContent(configJsonObject, this.host, dirPath, /*existingOptions*/ {}, configFilename);
errors = concatenate(errors, parsedCommandLine.errors);
Debug.assert(!!parsedCommandLine.fileNames);
if (parsedCommandLine.fileNames.length === 0) {
errors.push(createCompilerDiagnostic(Diagnostics.The_config_file_0_found_doesn_t_contain_any_source_files, configFilename));
return { errors };
}
else {
const parsedCommandLine = ts.parseJsonConfigFileContent(rawConfig.config, this.host, dirPath, /*existingOptions*/ {}, configFilename);
Debug.assert(!!parsedCommandLine.fileNames);
if (parsedCommandLine.errors && (parsedCommandLine.errors.length > 0)) {
return { succeeded: false, errors: parsedCommandLine.errors };
}
else if (parsedCommandLine.fileNames.length === 0) {
const error = createCompilerDiagnostic(Diagnostics.The_config_file_0_found_doesn_t_contain_any_source_files, configFilename);
return { succeeded: false, errors: [error] };
}
else {
const projectOptions: ProjectOptions = {
files: parsedCommandLine.fileNames,
wildcardDirectories: parsedCommandLine.wildcardDirectories,
compilerOptions: parsedCommandLine.options,
};
return { succeeded: true, projectOptions };
}
// if the project has some files, we can continue with the parsed options and tolerate
// errors in the parsedCommandLine
const projectOptions: ProjectOptions = {
files: parsedCommandLine.fileNames,
wildcardDirectories: parsedCommandLine.wildcardDirectories,
compilerOptions: parsedCommandLine.options,
};
return { projectOptions, errors };
}
}
@@ -1377,64 +1386,63 @@ namespace ts.server {
return false;
}
openConfigFile(configFilename: string, clientFileName?: string): { success: boolean, project?: Project, errors?: Diagnostic[] } {
const { succeeded, projectOptions, errors } = this.configFileToProjectOptions(configFilename);
if (!succeeded) {
return { success: false, errors };
openConfigFile(configFilename: string, clientFileName?: string): { project?: Project, errors: Diagnostic[] } {
const parseConfigFileResult = this.configFileToProjectOptions(configFilename);
let errors = parseConfigFileResult.errors;
if (!parseConfigFileResult.projectOptions) {
return { errors };
}
else {
if (!projectOptions.compilerOptions.disableSizeLimit && projectOptions.compilerOptions.allowJs) {
if (this.exceedTotalNonTsFileSizeLimit(projectOptions.files)) {
const project = this.createProject(configFilename, projectOptions, /*languageServiceDisabled*/ true);
const projectOptions = parseConfigFileResult.projectOptions;
if (!projectOptions.compilerOptions.disableSizeLimit && projectOptions.compilerOptions.allowJs) {
if (this.exceedTotalNonTsFileSizeLimit(projectOptions.files)) {
const project = this.createProject(configFilename, projectOptions, /*languageServiceDisabled*/ true);
// for configured projects with languageService disabled, we only watch its config file,
// do not care about the directory changes in the folder.
project.projectFileWatcher = this.host.watchFile(
toPath(configFilename, configFilename, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)),
_ => this.watchedProjectConfigFileChanged(project));
return { success: true, project };
}
// for configured projects with languageService disabled, we only watch its config file,
// do not care about the directory changes in the folder.
project.projectFileWatcher = this.host.watchFile(
toPath(configFilename, configFilename, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)),
_ => this.watchedProjectConfigFileChanged(project));
return { project, errors };
}
}
const project = this.createProject(configFilename, projectOptions);
for (const rootFilename of projectOptions.files) {
if (this.host.fileExists(rootFilename)) {
const info = this.openFile(rootFilename, /*openedByClient*/ clientFileName == rootFilename);
project.addRoot(info);
}
else {
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.File_0_not_found, rootFilename));
}
}
project.finishGraph();
project.projectFileWatcher = this.host.watchFile(configFilename, _ => this.watchedProjectConfigFileChanged(project));
const configDirectoryPath = ts.getDirectoryPath(configFilename);
this.log("Add recursive watcher for: " + configDirectoryPath);
project.directoryWatcher = this.host.watchDirectory(
configDirectoryPath,
path => this.directoryWatchedForSourceFilesChanged(project, path),
/*recursive*/ true
);
project.directoriesWatchedForWildcards = reduceProperties(createMap(projectOptions.wildcardDirectories), (watchers, flag, directory) => {
if (comparePaths(configDirectoryPath, directory, ".", !this.host.useCaseSensitiveFileNames) !== Comparison.EqualTo) {
const recursive = (flag & WatchDirectoryFlags.Recursive) !== 0;
this.log(`Add ${ recursive ? "recursive " : ""}watcher for: ${directory}`);
watchers[directory] = this.host.watchDirectory(
directory,
path => this.directoryWatchedForSourceFilesChanged(project, path),
recursive
);
}
const project = this.createProject(configFilename, projectOptions);
let errors: Diagnostic[];
for (const rootFilename of projectOptions.files) {
if (this.host.fileExists(rootFilename)) {
const info = this.openFile(rootFilename, /*openedByClient*/ clientFileName == rootFilename);
project.addRoot(info);
}
else {
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.File_0_not_found, rootFilename));
}
}
project.finishGraph();
project.projectFileWatcher = this.host.watchFile(configFilename, _ => this.watchedProjectConfigFileChanged(project));
return watchers;
}, <Map<FileWatcher>>{});
const configDirectoryPath = ts.getDirectoryPath(configFilename);
this.log("Add recursive watcher for: " + configDirectoryPath);
project.directoryWatcher = this.host.watchDirectory(
configDirectoryPath,
path => this.directoryWatchedForSourceFilesChanged(project, path),
/*recursive*/ true
);
project.directoriesWatchedForWildcards = reduceProperties(createMap(projectOptions.wildcardDirectories), (watchers, flag, directory) => {
if (comparePaths(configDirectoryPath, directory, ".", !this.host.useCaseSensitiveFileNames) !== Comparison.EqualTo) {
const recursive = (flag & WatchDirectoryFlags.Recursive) !== 0;
this.log(`Add ${ recursive ? "recursive " : ""}watcher for: ${directory}`);
watchers[directory] = this.host.watchDirectory(
directory,
path => this.directoryWatchedForSourceFilesChanged(project, path),
recursive
);
}
return watchers;
}, <Map<FileWatcher>>{});
return { success: true, project: project, errors };
}
return { project: project, errors };
}
updateConfiguredProject(project: Project): Diagnostic[] {
@@ -1443,15 +1451,15 @@ namespace ts.server {
this.removeProject(project);
}
else {
const { succeeded, projectOptions, errors } = this.configFileToProjectOptions(project.projectFilename);
if (!succeeded) {
const { projectOptions, errors } = this.configFileToProjectOptions(project.projectFilename);
if (!projectOptions) {
return errors;
}
else {
if (projectOptions.compilerOptions && !projectOptions.compilerOptions.disableSizeLimit && this.exceedTotalNonTsFileSizeLimit(projectOptions.files)) {
project.setProjectOptions(projectOptions);
if (project.languageServiceDiabled) {
return;
return errors;
}
project.disableLanguageService();
@@ -1459,7 +1467,7 @@ namespace ts.server {
project.directoryWatcher.close();
project.directoryWatcher = undefined;
}
return;
return errors;
}
if (project.languageServiceDiabled) {
@@ -1478,7 +1486,7 @@ namespace ts.server {
}
}
project.finishGraph();
return;
return errors;
}
// if the project is too large, the root files might not have been all loaded if the total
@@ -1506,13 +1514,13 @@ namespace ts.server {
// openFileRoots or openFileReferenced.
if (info.isOpen) {
if (this.openFileRoots.indexOf(info) >= 0) {
this.openFileRoots = copyListRemovingItem(info, this.openFileRoots);
unorderedRemoveItem(this.openFileRoots, info);
if (info.defaultProject && !info.defaultProject.isConfiguredProject()) {
this.removeProject(info.defaultProject);
}
}
if (this.openFilesReferenced.indexOf(info) >= 0) {
this.openFilesReferenced = copyListRemovingItem(info, this.openFilesReferenced);
unorderedRemoveItem(this.openFilesReferenced, info);
}
this.openFileRootsConfigured.push(info);
info.defaultProject = project;
@@ -1524,6 +1532,7 @@ namespace ts.server {
project.setProjectOptions(projectOptions);
project.finishGraph();
}
return errors;
}
}
+2 -2
View File
@@ -204,7 +204,7 @@ namespace ts.server {
// average async stat takes about 30 microseconds
// set chunk size to do 30 files in < 1 millisecond
function createPollingWatchedFileSet(interval = 2500, chunkSize = 30) {
let watchedFiles: WatchedFile[] = [];
const watchedFiles: WatchedFile[] = [];
let nextFileToCheck = 0;
let watchTimer: any;
@@ -267,7 +267,7 @@ namespace ts.server {
}
function removeFile(file: WatchedFile) {
watchedFiles = copyListRemovingItem(file, watchedFiles);
unorderedRemoveItem(watchedFiles, file);
}
return {
+13 -7
View File
@@ -153,16 +153,22 @@ namespace ts.server {
private logger: Logger
) {
this.projectService =
new ProjectService(host, logger, (eventName, project, fileName) => {
this.handleEvent(eventName, project, fileName);
new ProjectService(host, logger, event => {
this.handleEvent(event);
});
}
private handleEvent(eventName: string, project: Project, fileName: string) {
if (eventName == "context") {
this.projectService.log("got context event, updating diagnostics for" + fileName, "Info");
this.updateErrorCheck([{ fileName, project }], this.changeSeq,
(n) => n === this.changeSeq, 100);
private handleEvent(event: ProjectServiceEvent) {
switch (event.eventName) {
case "context":
const { project, fileName } = event.data;
this.projectService.log("got context event, updating diagnostics for" + fileName, "Info");
this.updateErrorCheck([{ fileName, project }], this.changeSeq,
(n) => n === this.changeSeq, 100);
break;
case "configFileDiag":
const { triggerFile, configFileName, diagnostics } = event.data;
this.configFileDiagnosticEvent(triggerFile, configFileName, diagnostics);
}
}
+1
View File
@@ -466,6 +466,7 @@ namespace ts.NavigationBar {
case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.VariableDeclaration:
return hasSomeImportantChild(item);
case SyntaxKind.ArrowFunction:
+211 -28
View File
@@ -280,11 +280,14 @@ namespace ts {
let pos = this.pos;
const useJSDocScanner = this.kind >= SyntaxKind.FirstJSDocTagNode && this.kind <= SyntaxKind.LastJSDocTagNode;
const processNode = (node: Node) => {
if (pos < node.pos) {
const isJSDocTagNode = isJSDocTag(node);
if (!isJSDocTagNode && pos < node.pos) {
pos = this.addSyntheticNodes(children, pos, node.pos, useJSDocScanner);
}
children.push(node);
pos = node.end;
if (!isJSDocTagNode) {
pos = node.end;
}
};
const processNodes = (nodes: NodeArray<Node>) => {
if (pos < nodes.pos) {
@@ -1369,8 +1372,12 @@ namespace ts {
containerName: string;
}
export interface ReferencedSymbolDefinitionInfo extends DefinitionInfo {
displayParts: SymbolDisplayPart[];
}
export interface ReferencedSymbol {
definition: DefinitionInfo;
definition: ReferencedSymbolDefinitionInfo;
references: ReferenceEntry[];
}
@@ -2784,18 +2791,42 @@ namespace ts {
return node && node.parent && node.parent.kind === SyntaxKind.PropertyAccessExpression && (<PropertyAccessExpression>node.parent).name === node;
}
function climbPastPropertyAccess(node: Node) {
return isRightSideOfPropertyAccess(node) ? node.parent : node;
}
/** Get `C` given `N` if `N` is in the position `class C extends N` or `class C extends foo.N` where `N` is an identifier. */
function tryGetClassByExtendingIdentifier(node: Node): ClassLikeDeclaration | undefined {
return tryGetClassExtendingExpressionWithTypeArguments(climbPastPropertyAccess(node).parent);
}
function isCallExpressionTarget(node: Node): boolean {
if (isRightSideOfPropertyAccess(node)) {
node = node.parent;
}
return node && node.parent && node.parent.kind === SyntaxKind.CallExpression && (<CallExpression>node.parent).expression === node;
return isCallOrNewExpressionTarget(node, SyntaxKind.CallExpression);
}
function isNewExpressionTarget(node: Node): boolean {
if (isRightSideOfPropertyAccess(node)) {
node = node.parent;
}
return node && node.parent && node.parent.kind === SyntaxKind.NewExpression && (<CallExpression>node.parent).expression === node;
return isCallOrNewExpressionTarget(node, SyntaxKind.NewExpression);
}
function isCallOrNewExpressionTarget(node: Node, kind: SyntaxKind) {
const target = climbPastPropertyAccess(node);
return target && target.parent && target.parent.kind === kind && (<CallExpression>target.parent).expression === target;
}
function climbPastManyPropertyAccesses(node: Node): Node {
return isRightSideOfPropertyAccess(node) ? climbPastManyPropertyAccesses(node.parent) : node;
}
/** Returns a CallLikeExpression where `node` is the target being invoked. */
function getAncestorCallLikeExpression(node: Node): CallLikeExpression | undefined {
const target = climbPastManyPropertyAccesses(node);
const callLike = target.parent;
return callLike && isCallLikeExpression(callLike) && getInvokedExpression(callLike) === target && callLike;
}
function tryGetSignatureDeclaration(typeChecker: TypeChecker, node: Node): SignatureDeclaration | undefined {
const callLike = getAncestorCallLikeExpression(node);
return callLike && typeChecker.getResolvedSignature(callLike).declaration;
}
function isNameOfModuleDeclaration(node: Node) {
@@ -4601,7 +4632,7 @@ namespace ts {
const symbolFlags = symbol.flags;
let symbolKind = getSymbolKindOfConstructorPropertyMethodAccessorFunctionOrVar(symbol, symbolFlags, location);
let hasAddedSymbolInfo: boolean;
const isThisExpression: boolean = location.kind === SyntaxKind.ThisKeyword && isExpression(location);
const isThisExpression = location.kind === SyntaxKind.ThisKeyword && isExpression(location);
let type: Type;
// Class at constructor site need to be shown as constructor apart from property,method, vars
@@ -4916,6 +4947,28 @@ namespace ts {
if (!documentation) {
documentation = symbol.getDocumentationComment();
if (documentation.length === 0 && symbol.flags & SymbolFlags.Property) {
// For some special property access expressions like `experts.foo = foo` or `module.exports.foo = foo`
// there documentation comments might be attached to the right hand side symbol of their declarations.
// The pattern of such special property access is that the parent symbol is the symbol of the file.
if (symbol.parent && forEach(symbol.parent.declarations, declaration => declaration.kind === SyntaxKind.SourceFile)) {
for (const declaration of symbol.declarations) {
if (!declaration.parent || declaration.parent.kind !== SyntaxKind.BinaryExpression) {
continue;
}
const rhsSymbol = program.getTypeChecker().getSymbolAtLocation((<BinaryExpression>declaration.parent).right);
if (!rhsSymbol) {
continue;
}
documentation = rhsSymbol.getDocumentationComment();
if (documentation.length > 0) {
break;
}
}
}
}
}
return { displayParts, documentation, symbolKind };
@@ -5042,14 +5095,25 @@ namespace ts {
};
}
function getSymbolInfo(typeChecker: TypeChecker, symbol: Symbol, node: Node) {
return {
symbolName: typeChecker.symbolToString(symbol), // Do not get scoped name, just the name of the symbol
symbolKind: getSymbolKind(symbol, node),
containerName: symbol.parent ? typeChecker.symbolToString(symbol.parent, node) : ""
};
}
function createDefinitionFromSignatureDeclaration(decl: SignatureDeclaration): DefinitionInfo {
const typeChecker = program.getTypeChecker();
const { symbolName, symbolKind, containerName } = getSymbolInfo(typeChecker, decl.symbol, decl);
return createDefinitionInfo(decl, symbolKind, symbolName, containerName);
}
function getDefinitionFromSymbol(symbol: Symbol, node: Node): DefinitionInfo[] {
const typeChecker = program.getTypeChecker();
const result: DefinitionInfo[] = [];
const declarations = symbol.getDeclarations();
const symbolName = typeChecker.symbolToString(symbol); // Do not get scoped name, just the name of the symbol
const symbolKind = getSymbolKind(symbol, node);
const containerSymbol = symbol.parent;
const containerName = containerSymbol ? typeChecker.symbolToString(containerSymbol, node) : "";
const { symbolName, symbolKind, containerName } = getSymbolInfo(typeChecker, symbol, node);
if (!tryAddConstructSignature(symbol, node, symbolKind, symbolName, containerName, result) &&
!tryAddCallSignature(symbol, node, symbolKind, symbolName, containerName, result)) {
@@ -5175,6 +5239,12 @@ namespace ts {
}
const typeChecker = program.getTypeChecker();
const calledDeclaration = tryGetSignatureDeclaration(typeChecker, node);
if (calledDeclaration) {
return [createDefinitionFromSignatureDeclaration(calledDeclaration)];
}
let symbol = typeChecker.getSymbolAtLocation(node);
// Could not find a symbol e.g. node is string or number keyword,
@@ -5982,6 +6052,7 @@ namespace ts {
case SyntaxKind.Identifier:
case SyntaxKind.ThisKeyword:
// case SyntaxKind.SuperKeyword: TODO:GH#9268
case SyntaxKind.ConstructorKeyword:
case SyntaxKind.StringLiteral:
return getReferencedSymbolsForNode(node, program.getSourceFiles(), findInStrings, findInComments);
}
@@ -6026,6 +6097,8 @@ namespace ts {
return getReferencesForSuperKeyword(node);
}
// `getSymbolAtLocation` normally returns the symbol of the class when given the constructor keyword,
// so we have to specify that we want the constructor symbol.
const symbol = typeChecker.getSymbolAtLocation(node);
if (!symbol && node.kind === SyntaxKind.StringLiteral) {
@@ -6081,7 +6154,7 @@ namespace ts {
return result;
function getDefinition(symbol: Symbol): DefinitionInfo {
function getDefinition(symbol: Symbol): ReferencedSymbolDefinitionInfo {
const info = getSymbolDisplayPartsDocumentationAndSymbolKind(symbol, node.getSourceFile(), getContainerNode(node), node);
const name = map(info.displayParts, p => p.text).join("");
const declarations = symbol.declarations;
@@ -6095,11 +6168,12 @@ namespace ts {
name,
kind: info.symbolKind,
fileName: declarations[0].getSourceFile().fileName,
textSpan: createTextSpan(declarations[0].getStart(), 0)
textSpan: createTextSpan(declarations[0].getStart(), 0),
displayParts: info.displayParts
};
}
function getAliasSymbolForPropertyNameSymbol(symbol: Symbol, location: Node): Symbol {
function getAliasSymbolForPropertyNameSymbol(symbol: Symbol, location: Node): Symbol | undefined {
if (symbol.flags & SymbolFlags.Alias) {
// Default import get alias
const defaultImport = getDeclarationOfKind(symbol, SyntaxKind.ImportClause);
@@ -6125,6 +6199,10 @@ namespace ts {
return undefined;
}
function followAliasIfNecessary(symbol: Symbol, location: Node): Symbol {
return getAliasSymbolForPropertyNameSymbol(symbol, location) || symbol;
}
function getPropertySymbolOfDestructuringAssignment(location: Node) {
return isArrayLiteralOrObjectLiteralDestructuringPattern(location.parent.parent) &&
typeChecker.getPropertySymbolOfDestructuringAssignment(<Identifier>location);
@@ -6290,13 +6368,14 @@ namespace ts {
}
});
const definition: DefinitionInfo = {
const definition: ReferencedSymbolDefinitionInfo = {
containerKind: "",
containerName: "",
fileName: targetLabel.getSourceFile().fileName,
kind: ScriptElementKind.label,
name: labelName,
textSpan: createTextSpanFromBounds(targetLabel.getStart(), targetLabel.getEnd())
textSpan: createTextSpanFromBounds(targetLabel.getStart(), targetLabel.getEnd()),
displayParts: [displayPart(labelName, SymbolDisplayPartKind.text)]
};
return [{ definition, references }];
@@ -6388,7 +6467,8 @@ namespace ts {
if (referenceSymbol) {
const referenceSymbolDeclaration = referenceSymbol.valueDeclaration;
const shorthandValueSymbol = typeChecker.getShorthandAssignmentValueSymbol(referenceSymbolDeclaration);
const relatedSymbol = getRelatedSymbol(searchSymbols, referenceSymbol, referenceLocation);
const relatedSymbol = getRelatedSymbol(searchSymbols, referenceSymbol, referenceLocation,
/*searchLocationIsConstructor*/ searchLocation.kind === SyntaxKind.ConstructorKeyword);
if (relatedSymbol) {
const referencedSymbol = getReferencedSymbol(relatedSymbol);
@@ -6404,12 +6484,94 @@ namespace ts {
const referencedSymbol = getReferencedSymbol(shorthandValueSymbol);
referencedSymbol.references.push(getReferenceEntryFromNode(referenceSymbolDeclaration.name));
}
else if (searchLocation.kind === SyntaxKind.ConstructorKeyword) {
findAdditionalConstructorReferences(referenceSymbol, referenceLocation);
}
}
});
}
return;
/** Adds references when a constructor is used with `new this()` in its own class and `super()` calls in subclasses. */
function findAdditionalConstructorReferences(referenceSymbol: Symbol, referenceLocation: Node): void {
Debug.assert(isClassLike(searchSymbol.valueDeclaration));
const referenceClass = referenceLocation.parent;
if (referenceSymbol === searchSymbol && isClassLike(referenceClass)) {
Debug.assert(referenceClass.name === referenceLocation);
// This is the class declaration containing the constructor.
addReferences(findOwnConstructorCalls(searchSymbol));
}
else {
// If this class appears in `extends C`, then the extending class' "super" calls are references.
const classExtending = tryGetClassByExtendingIdentifier(referenceLocation);
if (classExtending && isClassLike(classExtending) && followAliasIfNecessary(referenceSymbol, referenceLocation) === searchSymbol) {
addReferences(superConstructorAccesses(classExtending));
}
}
}
function addReferences(references: Node[]): void {
if (references.length) {
const referencedSymbol = getReferencedSymbol(searchSymbol);
addRange(referencedSymbol.references, map(references, getReferenceEntryFromNode));
}
}
/** `classSymbol` is the class where the constructor was defined.
* Reference the constructor and all calls to `new this()`.
*/
function findOwnConstructorCalls(classSymbol: Symbol): Node[] {
const result: Node[] = [];
for (const decl of classSymbol.members["__constructor"].declarations) {
Debug.assert(decl.kind === SyntaxKind.Constructor);
const ctrKeyword = decl.getChildAt(0);
Debug.assert(ctrKeyword.kind === SyntaxKind.ConstructorKeyword);
result.push(ctrKeyword);
}
forEachProperty(classSymbol.exports, member => {
const decl = member.valueDeclaration;
if (decl && decl.kind === SyntaxKind.MethodDeclaration) {
const body = (<MethodDeclaration>decl).body;
if (body) {
forEachDescendantOfKind(body, SyntaxKind.ThisKeyword, thisKeyword => {
if (isNewExpressionTarget(thisKeyword)) {
result.push(thisKeyword);
}
});
}
}
});
return result;
}
/** Find references to `super` in the constructor of an extending class. */
function superConstructorAccesses(cls: ClassLikeDeclaration): Node[] {
const symbol = cls.symbol;
const ctr = symbol.members["__constructor"];
if (!ctr) {
return [];
}
const result: Node[] = [];
for (const decl of ctr.declarations) {
Debug.assert(decl.kind === SyntaxKind.Constructor);
const body = (<ConstructorDeclaration>decl).body;
if (body) {
forEachDescendantOfKind(body, SyntaxKind.SuperKeyword, node => {
if (isCallExpressionTarget(node)) {
result.push(node);
}
});
}
};
return result;
}
function getReferencedSymbol(symbol: Symbol): ReferencedSymbol {
const symbolId = getSymbolId(symbol);
let index = symbolToIndex[symbolId];
@@ -6536,6 +6698,11 @@ namespace ts {
getThisReferencesInFile(sourceFile, searchSpaceNode, possiblePositions, references);
}
const thisOrSuperSymbol = typeChecker.getSymbolAtLocation(thisOrSuperKeyword);
const displayParts = thisOrSuperSymbol && getSymbolDisplayPartsDocumentationAndSymbolKind(
thisOrSuperSymbol, thisOrSuperKeyword.getSourceFile(), getContainerNode(thisOrSuperKeyword), thisOrSuperKeyword).displayParts;
return [{
definition: {
containerKind: "",
@@ -6543,7 +6710,8 @@ namespace ts {
fileName: node.getSourceFile().fileName,
kind: ScriptElementKind.variableElement,
name: "this",
textSpan: createTextSpanFromBounds(node.getStart(), node.getEnd())
textSpan: createTextSpanFromBounds(node.getStart(), node.getEnd()),
displayParts
},
references: references
}];
@@ -6614,7 +6782,8 @@ namespace ts {
fileName: node.getSourceFile().fileName,
kind: ScriptElementKind.variableElement,
name: type.text,
textSpan: createTextSpanFromBounds(node.getStart(), node.getEnd())
textSpan: createTextSpanFromBounds(node.getStart(), node.getEnd()),
displayParts: [displayPart(getTextOfNode(node), SymbolDisplayPartKind.stringLiteral)]
},
references: references
}];
@@ -6783,16 +6952,17 @@ namespace ts {
}
}
function getRelatedSymbol(searchSymbols: Symbol[], referenceSymbol: Symbol, referenceLocation: Node): Symbol {
if (searchSymbols.indexOf(referenceSymbol) >= 0) {
return referenceSymbol;
function getRelatedSymbol(searchSymbols: Symbol[], referenceSymbol: Symbol, referenceLocation: Node, searchLocationIsConstructor: boolean): Symbol | undefined {
if (contains(searchSymbols, referenceSymbol)) {
// If we are searching for constructor uses, they must be 'new' expressions.
return (!searchLocationIsConstructor || isNewExpressionTarget(referenceLocation)) && referenceSymbol;
}
// If the reference symbol is an alias, check if what it is aliasing is one of the search
// symbols but by looking up for related symbol of this alias so it can handle multiple level of indirectness.
const aliasSymbol = getAliasSymbolForPropertyNameSymbol(referenceSymbol, referenceLocation);
if (aliasSymbol) {
return getRelatedSymbol(searchSymbols, aliasSymbol, referenceLocation);
return getRelatedSymbol(searchSymbols, aliasSymbol, referenceLocation, searchLocationIsConstructor);
}
// If the reference location is in an object literal, try to get the contextual type for the
@@ -7573,6 +7743,10 @@ namespace ts {
* False will mean that node is not classified and traverse routine should recurse into node contents.
*/
function tryClassifyNode(node: Node): boolean {
if (isJSDocTag(node)) {
return true;
}
if (nodeIsMissing(node)) {
return true;
}
@@ -8312,6 +8486,15 @@ namespace ts {
};
}
function forEachDescendantOfKind(node: Node, kind: SyntaxKind, action: (node: Node) => void) {
forEachChild(node, child => {
if (child.kind === kind) {
action(child);
}
forEachDescendantOfKind(child, kind, action);
});
}
/* @internal */
export function getNameTable(sourceFile: SourceFile): Map<number> {
if (!sourceFile.nameTable) {
+1 -1
View File
@@ -1203,6 +1203,6 @@ namespace TypeScript.Services {
// TODO: it should be moved into a namespace though.
/* @internal */
const toolsVersion = "1.9";
const toolsVersion = "2.1";
/* tslint:enable:no-unused-variable */
+21
View File
@@ -925,4 +925,25 @@ namespace ts {
}
return ensureScriptKind(fileName, scriptKind);
}
export function parseAndReEmitConfigJSONFile(content: string) {
const options: TranspileOptions = {
fileName: "config.js",
compilerOptions: {
target: ScriptTarget.ES6,
removeComments: true
},
reportDiagnostics: true
};
const { outputText, diagnostics } = ts.transpileModule("(" + content + ")", options);
// Becasue the content was wrapped in "()", the start position of diagnostics needs to be subtract by 1
// also, the emitted result will have "(" in the beginning and ");" in the end. We need to strip these
// as well
const trimmedOutput = outputText.trim();
const configJsonObject = JSON.parse(trimmedOutput.substring(1, trimmedOutput.length - 2));
for (const diagnostic of diagnostics) {
diagnostic.start = diagnostic.start - 1;
}
return { configJsonObject, diagnostics };
}
}