mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into wip-master-statelessOverload
This commit is contained in:
+111
-70
@@ -1,4 +1,4 @@
|
||||
/// <reference path="moduleNameResolver.ts"/>
|
||||
/// <reference path="moduleNameResolver.ts"/>
|
||||
/// <reference path="binder.ts"/>
|
||||
|
||||
/* @internal */
|
||||
@@ -3737,11 +3737,16 @@ namespace ts {
|
||||
return getObjectFlags(type) & ObjectFlags.Reference ? (<TypeReference>type).target : type;
|
||||
}
|
||||
|
||||
function hasBaseType(type: InterfaceType, checkBase: InterfaceType) {
|
||||
function hasBaseType(type: BaseType, checkBase: BaseType) {
|
||||
return check(type);
|
||||
function check(type: InterfaceType): boolean {
|
||||
const target = <InterfaceType>getTargetType(type);
|
||||
return target === checkBase || forEach(getBaseTypes(target), check);
|
||||
function check(type: BaseType): boolean {
|
||||
if (getObjectFlags(type) & (ObjectFlags.ClassOrInterface | ObjectFlags.Reference)) {
|
||||
const target = <InterfaceType>getTargetType(type);
|
||||
return target === checkBase || forEach(getBaseTypes(target), check);
|
||||
}
|
||||
else if (type.flags & TypeFlags.Intersection) {
|
||||
return forEach((<IntersectionType>type).types, check);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3810,7 +3815,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isConstructorType(type: Type): boolean {
|
||||
return type.flags & TypeFlags.Object && getSignaturesOfType(type, SignatureKind.Construct).length > 0;
|
||||
return isValidBaseType(type) && getSignaturesOfType(type, SignatureKind.Construct).length > 0;
|
||||
}
|
||||
|
||||
function getBaseTypeNodeOfClass(type: InterfaceType): ExpressionWithTypeArguments {
|
||||
@@ -3849,7 +3854,7 @@ namespace ts {
|
||||
return unknownType;
|
||||
}
|
||||
const baseConstructorType = checkExpression(baseTypeNode.expression);
|
||||
if (baseConstructorType.flags & TypeFlags.Object) {
|
||||
if (baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection)) {
|
||||
// Resolving the members of a class requires us to resolve the base class of that class.
|
||||
// We force resolution here such that we catch circularities now.
|
||||
resolveStructuredTypeMembers(<ObjectType>baseConstructorType);
|
||||
@@ -3867,7 +3872,7 @@ namespace ts {
|
||||
return type.resolvedBaseConstructorType;
|
||||
}
|
||||
|
||||
function getBaseTypes(type: InterfaceType): ObjectType[] {
|
||||
function getBaseTypes(type: InterfaceType): BaseType[] {
|
||||
if (!type.resolvedBaseTypes) {
|
||||
if (type.objectFlags & ObjectFlags.Tuple) {
|
||||
type.resolvedBaseTypes = [createArrayType(getUnionType(type.typeParameters))];
|
||||
@@ -3890,7 +3895,7 @@ namespace ts {
|
||||
function resolveBaseTypesOfClass(type: InterfaceType): void {
|
||||
type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray;
|
||||
const baseConstructorType = <ObjectType>getBaseConstructorTypeOfClass(type);
|
||||
if (!(baseConstructorType.flags & TypeFlags.Object)) {
|
||||
if (!(baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection))) {
|
||||
return;
|
||||
}
|
||||
const baseTypeNode = getBaseTypeNodeOfClass(type);
|
||||
@@ -3927,11 +3932,11 @@ namespace ts {
|
||||
if (baseType === unknownType) {
|
||||
return;
|
||||
}
|
||||
if (!(getObjectFlags(getTargetType(baseType)) & ObjectFlags.ClassOrInterface)) {
|
||||
if (!isValidBaseType(baseType)) {
|
||||
error(baseTypeNode.expression, Diagnostics.Base_constructor_return_type_0_is_not_a_class_or_interface_type, typeToString(baseType));
|
||||
return;
|
||||
}
|
||||
if (type === baseType || hasBaseType(<InterfaceType>baseType, type)) {
|
||||
if (type === baseType || hasBaseType(<BaseType>baseType, type)) {
|
||||
error(valueDecl, Diagnostics.Type_0_recursively_references_itself_as_a_base_type,
|
||||
typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType));
|
||||
return;
|
||||
@@ -3956,6 +3961,13 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
// A valid base type is any non-generic object type or intersection of non-generic
|
||||
// object types.
|
||||
function isValidBaseType(type: Type): boolean {
|
||||
return type.flags & TypeFlags.Object && !isGenericMappedType(type) ||
|
||||
type.flags & TypeFlags.Intersection && !forEach((<IntersectionType>type).types, t => !isValidBaseType(t));
|
||||
}
|
||||
|
||||
function resolveBaseTypesOfInterface(type: InterfaceType): void {
|
||||
type.resolvedBaseTypes = type.resolvedBaseTypes || emptyArray;
|
||||
for (const declaration of type.symbol.declarations) {
|
||||
@@ -3963,8 +3975,8 @@ namespace ts {
|
||||
for (const node of getInterfaceBaseTypeNodes(<InterfaceDeclaration>declaration)) {
|
||||
const baseType = getTypeFromTypeNode(node);
|
||||
if (baseType !== unknownType) {
|
||||
if (getObjectFlags(getTargetType(baseType)) & ObjectFlags.ClassOrInterface) {
|
||||
if (type !== baseType && !hasBaseType(<InterfaceType>baseType, type)) {
|
||||
if (isValidBaseType(baseType)) {
|
||||
if (type !== baseType && !hasBaseType(<BaseType>baseType, type)) {
|
||||
if (type.resolvedBaseTypes === emptyArray) {
|
||||
type.resolvedBaseTypes = [<ObjectType>baseType];
|
||||
}
|
||||
@@ -4177,7 +4189,6 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getDeclaredTypeOfSymbol(symbol: Symbol): Type {
|
||||
Debug.assert((symbol.flags & SymbolFlags.Instantiated) === 0);
|
||||
if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
|
||||
return getDeclaredTypeOfClassOrInterface(symbol);
|
||||
}
|
||||
@@ -4319,8 +4330,14 @@ namespace ts {
|
||||
|
||||
function getTypeWithThisArgument(type: Type, thisArgument?: Type): Type {
|
||||
if (getObjectFlags(type) & ObjectFlags.Reference) {
|
||||
return createTypeReference((<TypeReference>type).target,
|
||||
concatenate((<TypeReference>type).typeArguments, [thisArgument || (<TypeReference>type).target.thisType]));
|
||||
const target = (<TypeReference>type).target;
|
||||
const typeArguments = (<TypeReference>type).typeArguments;
|
||||
if (length(target.typeParameters) === length(typeArguments)) {
|
||||
return createTypeReference(target, concatenate(typeArguments, [thisArgument || target.thisType]));
|
||||
}
|
||||
}
|
||||
else if (type.flags & TypeFlags.Intersection) {
|
||||
return getIntersectionType(map((<IntersectionType>type).types, t => getTypeWithThisArgument(t, thisArgument)));
|
||||
}
|
||||
return type;
|
||||
}
|
||||
@@ -4355,8 +4372,8 @@ namespace ts {
|
||||
}
|
||||
const thisArgument = lastOrUndefined(typeArguments);
|
||||
for (const baseType of baseTypes) {
|
||||
const instantiatedBaseType = thisArgument ? getTypeWithThisArgument(<ObjectType>instantiateType(baseType, mapper), thisArgument) : baseType;
|
||||
addInheritedMembers(members, getPropertiesOfObjectType(instantiatedBaseType));
|
||||
const instantiatedBaseType = thisArgument ? getTypeWithThisArgument(instantiateType(baseType, mapper), thisArgument) : baseType;
|
||||
addInheritedMembers(members, getPropertiesOfType(instantiatedBaseType));
|
||||
callSignatures = concatenate(callSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Call));
|
||||
constructSignatures = concatenate(constructSignatures, getSignaturesOfType(instantiatedBaseType, SignatureKind.Construct));
|
||||
stringIndexInfo = stringIndexInfo || getIndexInfoOfType(instantiatedBaseType, IndexKind.String);
|
||||
@@ -4578,9 +4595,9 @@ namespace ts {
|
||||
constructSignatures = getDefaultConstructSignatures(classType);
|
||||
}
|
||||
const baseConstructorType = getBaseConstructorTypeOfClass(classType);
|
||||
if (baseConstructorType.flags & TypeFlags.Object) {
|
||||
if (baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection)) {
|
||||
members = createSymbolTable(getNamedMembers(members));
|
||||
addInheritedMembers(members, getPropertiesOfObjectType(baseConstructorType));
|
||||
addInheritedMembers(members, getPropertiesOfType(baseConstructorType));
|
||||
}
|
||||
}
|
||||
const numberIndexInfo = symbol.flags & SymbolFlags.Enum ? enumNumberIndexInfo : undefined;
|
||||
@@ -4606,12 +4623,14 @@ namespace ts {
|
||||
const typeParameter = getTypeParameterFromMappedType(type);
|
||||
const constraintType = getConstraintTypeFromMappedType(type);
|
||||
const templateType = getTemplateTypeFromMappedType(type);
|
||||
const modifiersType = getApparentType(getModifiersTypeFromMappedType(type));
|
||||
const modifiersType = getApparentType(getModifiersTypeFromMappedType(type)); // The 'T' in 'keyof T'
|
||||
const templateReadonly = !!type.declaration.readonlyToken;
|
||||
const templateOptional = !!type.declaration.questionToken;
|
||||
if (type.declaration.typeParameter.constraint.kind === SyntaxKind.TypeOperator) {
|
||||
// We have a { [P in keyof T]: X }
|
||||
forEachType(getLiteralTypeFromPropertyNames(modifiersType), addMemberForKeyType);
|
||||
for (const propertySymbol of getPropertiesOfType(modifiersType)) {
|
||||
addMemberForKeyType(getLiteralTypeFromPropertyName(propertySymbol), propertySymbol);
|
||||
}
|
||||
if (getIndexInfoOfType(modifiersType, IndexKind.String)) {
|
||||
addMemberForKeyType(stringType);
|
||||
}
|
||||
@@ -4626,7 +4645,7 @@ namespace ts {
|
||||
}
|
||||
setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, undefined);
|
||||
|
||||
function addMemberForKeyType(t: Type) {
|
||||
function addMemberForKeyType(t: Type, propertySymbol?: Symbol) {
|
||||
// Create a mapper from T to the current iteration type constituent. Then, if the
|
||||
// mapped type is itself an instantiated type, combine the iteration mapper with the
|
||||
// instantiation mapper.
|
||||
@@ -4642,6 +4661,9 @@ namespace ts {
|
||||
const prop = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | (isOptional ? SymbolFlags.Optional : 0), propName);
|
||||
prop.type = propType;
|
||||
prop.isReadonly = templateReadonly || modifiersProp && isReadonlySymbol(modifiersProp);
|
||||
if (propertySymbol) {
|
||||
prop.mappedTypeOrigin = propertySymbol;
|
||||
}
|
||||
members.set(propName, prop);
|
||||
}
|
||||
else if (t.flags & TypeFlags.String) {
|
||||
@@ -4744,28 +4766,26 @@ namespace ts {
|
||||
}
|
||||
|
||||
function getPropertiesOfUnionOrIntersectionType(type: UnionOrIntersectionType): Symbol[] {
|
||||
for (const current of type.types) {
|
||||
for (const prop of getPropertiesOfType(current)) {
|
||||
getUnionOrIntersectionProperty(type, prop.name);
|
||||
}
|
||||
// The properties of a union type are those that are present in all constituent types, so
|
||||
// we only need to check the properties of the first type
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
const props = type.resolvedProperties;
|
||||
if (props) {
|
||||
const result: Symbol[] = [];
|
||||
props.forEach(prop => {
|
||||
// We need to filter out partial properties in union types
|
||||
if (!(prop.flags & SymbolFlags.SyntheticProperty && (<TransientSymbol>prop).isPartial)) {
|
||||
result.push(prop);
|
||||
if (!type.resolvedProperties) {
|
||||
const members = createMap<Symbol>();
|
||||
for (const current of type.types) {
|
||||
for (const prop of getPropertiesOfType(current)) {
|
||||
if (!members.has(prop.name)) {
|
||||
const combinedProp = getPropertyOfUnionOrIntersectionType(type, prop.name);
|
||||
if (combinedProp) {
|
||||
members.set(prop.name, combinedProp);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
// The properties of a union type are those that are present in all constituent types, so
|
||||
// we only need to check the properties of the first type
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
type.resolvedProperties = getNamedMembers(members);
|
||||
}
|
||||
return emptyArray;
|
||||
return type.resolvedProperties;
|
||||
}
|
||||
|
||||
function getPropertiesOfType(type: Type): Symbol[] {
|
||||
@@ -4850,6 +4870,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getApparentTypeOfIntersectionType(type: IntersectionType) {
|
||||
return type.resolvedIndexType || (type.resolvedApparentType = getTypeWithThisArgument(type, type));
|
||||
}
|
||||
|
||||
/**
|
||||
* For a type parameter, return the base constraint of the type parameter. For the string, number,
|
||||
* boolean, and symbol primitive types, return the corresponding object types. Otherwise return the
|
||||
@@ -4857,7 +4881,8 @@ namespace ts {
|
||||
*/
|
||||
function getApparentType(type: Type): Type {
|
||||
const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfType(<TypeVariable>type) || emptyObjectType : type;
|
||||
return t.flags & TypeFlags.StringLike ? globalStringType :
|
||||
return t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(<IntersectionType>t) :
|
||||
t.flags & TypeFlags.StringLike ? globalStringType :
|
||||
t.flags & TypeFlags.NumberLike ? globalNumberType :
|
||||
t.flags & TypeFlags.BooleanLike ? globalBooleanType :
|
||||
t.flags & TypeFlags.ESSymbol ? getGlobalESSymbolType() :
|
||||
@@ -4933,7 +4958,7 @@ namespace ts {
|
||||
// these partial properties when identifying discriminant properties, but otherwise they are filtered out
|
||||
// and do not appear to be present in the union type.
|
||||
function getUnionOrIntersectionProperty(type: UnionOrIntersectionType, name: string): Symbol {
|
||||
const properties = type.resolvedProperties || (type.resolvedProperties = createMap<Symbol>());
|
||||
const properties = type.propertyCache || (type.propertyCache = createMap<Symbol>());
|
||||
let property = properties.get(name);
|
||||
if (!property) {
|
||||
property = createUnionOrIntersectionProperty(type, name);
|
||||
@@ -6296,6 +6321,9 @@ namespace ts {
|
||||
if (right.flags & TypeFlags.Union) {
|
||||
return mapType(right, t => getSpreadType(left, t));
|
||||
}
|
||||
if (right.flags & TypeFlags.NonPrimitive) {
|
||||
return emptyObjectType;
|
||||
}
|
||||
|
||||
const members = createMap<Symbol>();
|
||||
const skippedPrivateMembers = createMap<boolean>();
|
||||
@@ -11812,7 +11840,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isValidSpreadType(type: Type): boolean {
|
||||
return !!(type.flags & (TypeFlags.Any | TypeFlags.Null | TypeFlags.Undefined) ||
|
||||
return !!(type.flags & (TypeFlags.Any | TypeFlags.Null | TypeFlags.Undefined | TypeFlags.NonPrimitive) ||
|
||||
type.flags & TypeFlags.Object && !isGenericMappedType(type) ||
|
||||
type.flags & TypeFlags.UnionOrIntersection && !forEach((<UnionOrIntersectionType>type).types, t => !isValidSpreadType(t)));
|
||||
}
|
||||
@@ -16067,12 +16095,12 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Static members being set on a constructor function may conflict with built-in properties
|
||||
* of Function. Esp. in ECMAScript 5 there are non-configurable and non-writable
|
||||
* built-in properties. This check issues a transpile error when a class has a static
|
||||
* of Function. Esp. in ECMAScript 5 there are non-configurable and non-writable
|
||||
* built-in properties. This check issues a transpile error when a class has a static
|
||||
* member with the same name as a non-writable built-in property.
|
||||
*
|
||||
*
|
||||
* @see http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.3
|
||||
* @see http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.5
|
||||
* @see http://www.ecma-international.org/ecma-262/6.0/#sec-properties-of-the-function-constructor
|
||||
@@ -18560,16 +18588,18 @@ namespace ts {
|
||||
return;
|
||||
}
|
||||
|
||||
const propDeclaration = prop.valueDeclaration;
|
||||
|
||||
// index is numeric and property name is not valid numeric literal
|
||||
if (indexKind === IndexKind.Number && !isNumericName(prop.valueDeclaration.name)) {
|
||||
if (indexKind === IndexKind.Number && !(propDeclaration ? isNumericName(propDeclaration.name) : isNumericLiteralName(prop.name))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// perform property check if property or indexer is declared in 'type'
|
||||
// this allows to rule out cases when both property and indexer are inherited from the base class
|
||||
let errorNode: Node;
|
||||
if (prop.valueDeclaration.name.kind === SyntaxKind.ComputedPropertyName || prop.parent === containingType.symbol) {
|
||||
errorNode = prop.valueDeclaration;
|
||||
if (propDeclaration && (propDeclaration.name.kind === SyntaxKind.ComputedPropertyName || prop.parent === containingType.symbol)) {
|
||||
errorNode = propDeclaration;
|
||||
}
|
||||
else if (indexDeclaration) {
|
||||
errorNode = indexDeclaration;
|
||||
@@ -18682,7 +18712,11 @@ namespace ts {
|
||||
const staticType = <ObjectType>getTypeOfSymbol(symbol);
|
||||
checkTypeParameterListsIdentical(node, symbol);
|
||||
checkClassForDuplicateDeclarations(node);
|
||||
checkClassForStaticPropertyNameConflicts(node);
|
||||
|
||||
// Only check for reserved static identifiers on non-ambient context.
|
||||
if (!isInAmbientContext(node)) {
|
||||
checkClassForStaticPropertyNameConflicts(node);
|
||||
}
|
||||
|
||||
const baseTypeNode = getClassExtendsHeritageClauseElement(node);
|
||||
if (baseTypeNode) {
|
||||
@@ -18708,7 +18742,7 @@ namespace ts {
|
||||
checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), node.name || node,
|
||||
Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1);
|
||||
|
||||
if (baseType.symbol.valueDeclaration &&
|
||||
if (baseType.symbol && baseType.symbol.valueDeclaration &&
|
||||
!isInAmbientContext(baseType.symbol.valueDeclaration) &&
|
||||
baseType.symbol.valueDeclaration.kind === SyntaxKind.ClassDeclaration) {
|
||||
if (!isBlockScopedNameDeclaredBeforeUse(baseType.symbol.valueDeclaration, node)) {
|
||||
@@ -18740,8 +18774,7 @@ namespace ts {
|
||||
if (produceDiagnostics) {
|
||||
const t = getTypeFromTypeNode(typeRefNode);
|
||||
if (t !== unknownType) {
|
||||
const declaredType = getObjectFlags(t) & ObjectFlags.Reference ? (<TypeReference>t).target : t;
|
||||
if (getObjectFlags(declaredType) & ObjectFlags.ClassOrInterface) {
|
||||
if (isValidBaseType(t)) {
|
||||
checkTypeAssignableTo(typeWithThis, getTypeWithThisArgument(t, type.thisType), node.name || node, Diagnostics.Class_0_incorrectly_implements_interface_1);
|
||||
}
|
||||
else {
|
||||
@@ -18781,7 +18814,7 @@ namespace ts {
|
||||
return forEach(symbol.declarations, d => isClassLike(d) ? d : undefined);
|
||||
}
|
||||
|
||||
function checkKindsOfPropertyMemberOverrides(type: InterfaceType, baseType: ObjectType): void {
|
||||
function checkKindsOfPropertyMemberOverrides(type: InterfaceType, baseType: BaseType): void {
|
||||
|
||||
// TypeScript 1.0 spec (April 2014): 8.2.3
|
||||
// A derived class inherits all members from its base class it doesn't override.
|
||||
@@ -18798,7 +18831,7 @@ namespace ts {
|
||||
// derived class instance member variables and accessors, but not by other kinds of members.
|
||||
|
||||
// NOTE: assignability is checked in checkClassDeclaration
|
||||
const baseProperties = getPropertiesOfObjectType(baseType);
|
||||
const baseProperties = getPropertiesOfType(baseType);
|
||||
for (const baseProperty of baseProperties) {
|
||||
const base = getTargetSymbol(baseProperty);
|
||||
|
||||
@@ -18922,7 +18955,7 @@ namespace ts {
|
||||
let ok = true;
|
||||
|
||||
for (const base of baseTypes) {
|
||||
const properties = getPropertiesOfObjectType(getTypeWithThisArgument(base, type.thisType));
|
||||
const properties = getPropertiesOfType(getTypeWithThisArgument(base, type.thisType));
|
||||
for (const prop of properties) {
|
||||
const existing = seen.get(prop.name);
|
||||
if (!existing) {
|
||||
@@ -20549,6 +20582,10 @@ namespace ts {
|
||||
const links = symbol as SymbolLinks;
|
||||
return [links.leftSpread, links.rightSpread];
|
||||
}
|
||||
if ((symbol as SymbolLinks).mappedTypeOrigin) {
|
||||
return getRootSymbols((symbol as SymbolLinks).mappedTypeOrigin);
|
||||
}
|
||||
|
||||
let target: Symbol;
|
||||
let next = symbol;
|
||||
while (next = getSymbolLinks(next).target) {
|
||||
@@ -20567,7 +20604,8 @@ namespace ts {
|
||||
if (!isGeneratedIdentifier(node)) {
|
||||
node = getParseTreeNode(node, isIdentifier);
|
||||
if (node) {
|
||||
return getReferencedValueSymbol(node) === argumentsSymbol;
|
||||
const isPropertyName = node.parent.kind === SyntaxKind.PropertyAccessExpression && (<PropertyAccessExpression>node.parent).name === node;
|
||||
return !isPropertyName && getReferencedValueSymbol(node) === argumentsSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20862,18 +20900,21 @@ namespace ts {
|
||||
function getTypeReferenceSerializationKind(typeName: EntityName, location?: Node): TypeReferenceSerializationKind {
|
||||
// Resolve the symbol as a value to ensure the type can be reached at runtime during emit.
|
||||
const valueSymbol = resolveEntityName(typeName, SymbolFlags.Value, /*ignoreErrors*/ true, /*dontResolveAlias*/ false, location);
|
||||
const globalPromiseSymbol = tryGetGlobalPromiseConstructorSymbol();
|
||||
if (globalPromiseSymbol && valueSymbol === globalPromiseSymbol) {
|
||||
return TypeReferenceSerializationKind.Promise;
|
||||
}
|
||||
|
||||
const constructorType = valueSymbol ? getTypeOfSymbol(valueSymbol) : undefined;
|
||||
if (constructorType && isConstructorType(constructorType)) {
|
||||
return TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue;
|
||||
}
|
||||
|
||||
// Resolve the symbol as a type so that we can provide a more useful hint for the type serializer.
|
||||
const typeSymbol = resolveEntityName(typeName, SymbolFlags.Type, /*ignoreErrors*/ true, /*dontResolveAlias*/ false, location);
|
||||
if (valueSymbol && valueSymbol === typeSymbol) {
|
||||
const globalPromiseSymbol = tryGetGlobalPromiseConstructorSymbol();
|
||||
if (globalPromiseSymbol && valueSymbol === globalPromiseSymbol) {
|
||||
return TypeReferenceSerializationKind.Promise;
|
||||
}
|
||||
|
||||
const constructorType = getTypeOfSymbol(valueSymbol);
|
||||
if (constructorType && isConstructorType(constructorType)) {
|
||||
return TypeReferenceSerializationKind.TypeWithConstructSignatureAndValue;
|
||||
}
|
||||
}
|
||||
|
||||
// We might not be able to resolve type symbol so use unknown type in that case (eg error case)
|
||||
if (!typeSymbol) {
|
||||
return TypeReferenceSerializationKind.ObjectType;
|
||||
|
||||
@@ -67,10 +67,11 @@ namespace ts {
|
||||
name: "jsx",
|
||||
type: createMapFromTemplate({
|
||||
"preserve": JsxEmit.Preserve,
|
||||
"react-native": JsxEmit.ReactNative,
|
||||
"react": JsxEmit.React
|
||||
}),
|
||||
paramType: Diagnostics.KIND,
|
||||
description: Diagnostics.Specify_JSX_code_generation_Colon_preserve_or_react,
|
||||
description: Diagnostics.Specify_JSX_code_generation_Colon_preserve_react_native_or_react,
|
||||
},
|
||||
{
|
||||
name: "reactNamespace",
|
||||
|
||||
@@ -204,6 +204,10 @@ namespace ts {
|
||||
GreaterThan = 1
|
||||
}
|
||||
|
||||
export function length(array: any[]) {
|
||||
return array ? array.length : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through 'array' by index and performs the callback on each element of array until the callback
|
||||
* returns a truthy value, then returns that value.
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace ts {
|
||||
|
||||
export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, targetSourceFile: SourceFile): Diagnostic[] {
|
||||
const declarationDiagnostics = createDiagnosticCollection();
|
||||
forEachExpectedEmitFile(host, getDeclarationDiagnosticsFromFile, targetSourceFile);
|
||||
forEachEmittedFile(host, getDeclarationDiagnosticsFromFile, targetSourceFile);
|
||||
return declarationDiagnostics.getDiagnostics(targetSourceFile ? targetSourceFile.fileName : undefined);
|
||||
|
||||
function getDeclarationDiagnosticsFromFile({ declarationFilePath }: EmitFileNames, sources: SourceFile[], isBundledEmit: boolean) {
|
||||
@@ -1788,7 +1788,7 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
// Get the declaration file path
|
||||
forEachExpectedEmitFile(host, getDeclFileName, referencedFile, emitOnlyDtsFiles);
|
||||
forEachEmittedFile(host, getDeclFileName, referencedFile, emitOnlyDtsFiles);
|
||||
}
|
||||
|
||||
if (declFileName) {
|
||||
|
||||
@@ -2713,7 +2713,7 @@
|
||||
"category": "Message",
|
||||
"code": 6079
|
||||
},
|
||||
"Specify JSX code generation: 'preserve' or 'react'": {
|
||||
"Specify JSX code generation: 'preserve', 'react-native', or 'react'": {
|
||||
"category": "Message",
|
||||
"code": 6080
|
||||
},
|
||||
|
||||
@@ -73,7 +73,7 @@ namespace ts {
|
||||
|
||||
// Emit each output file
|
||||
performance.mark("beforePrint");
|
||||
forEachTransformedEmitFile(host, transformed, emitFile, emitOnlyDtsFiles);
|
||||
forEachEmittedFile(host, emitFile, transformed, emitOnlyDtsFiles);
|
||||
performance.measure("printTime", "beforePrint");
|
||||
|
||||
// Clean up emit nodes on parse tree
|
||||
@@ -88,7 +88,7 @@ namespace ts {
|
||||
sourceMaps: sourceMapDataList
|
||||
};
|
||||
|
||||
function emitFile(jsFilePath: string, sourceMapFilePath: string, declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) {
|
||||
function emitFile({ jsFilePath, sourceMapFilePath, declarationFilePath }: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean) {
|
||||
// Make sure not to write js file and source map file if any of them cannot be written
|
||||
if (!host.isEmitBlocked(jsFilePath) && !compilerOptions.noEmit) {
|
||||
if (!emitOnlyDtsFiles) {
|
||||
|
||||
@@ -439,7 +439,7 @@ namespace ts {
|
||||
|
||||
function getCommonSourceDirectory() {
|
||||
if (commonSourceDirectory === undefined) {
|
||||
const emittedFiles = filterSourceFilesInDirectory(files, isSourceFileFromExternalLibrary);
|
||||
const emittedFiles = filter(files, file => sourceFileMayBeEmitted(file, options, isSourceFileFromExternalLibrary));
|
||||
if (options.rootDir && checkSourceFilesBelongToPath(emittedFiles, options.rootDir)) {
|
||||
// If a rootDir is specified and is valid use it as the commonSourceDirectory
|
||||
commonSourceDirectory = getNormalizedAbsolutePath(options.rootDir, currentDirectory);
|
||||
@@ -1707,7 +1707,7 @@ namespace ts {
|
||||
if (!options.noEmit && !options.suppressOutputPathCheck) {
|
||||
const emitHost = getEmitHost();
|
||||
const emitFilesSeen = createFileMap<boolean>(!host.useCaseSensitiveFileNames() ? key => key.toLocaleLowerCase() : undefined);
|
||||
forEachExpectedEmitFile(emitHost, (emitFileNames) => {
|
||||
forEachEmittedFile(emitHost, (emitFileNames) => {
|
||||
verifyEmitFilePath(emitFileNames.jsFilePath, emitFilesSeen);
|
||||
verifyEmitFilePath(emitFileNames.declarationFilePath, emitFilesSeen);
|
||||
});
|
||||
|
||||
@@ -585,7 +585,7 @@ namespace ts {
|
||||
if (isGeneratedIdentifier(node)) {
|
||||
return node;
|
||||
}
|
||||
if (node.text !== "arguments" && !resolver.isArgumentsLocalBinding(node)) {
|
||||
if (node.text !== "arguments" || !resolver.isArgumentsLocalBinding(node)) {
|
||||
return node;
|
||||
}
|
||||
return convertedLoopState.argumentsName || (convertedLoopState.argumentsName = createUniqueName("arguments"));
|
||||
|
||||
@@ -11,10 +11,10 @@ namespace ts {
|
||||
export function transformES5(context: TransformationContext) {
|
||||
const compilerOptions = context.getCompilerOptions();
|
||||
|
||||
// enable emit notification only if using --jsx preserve
|
||||
// enable emit notification only if using --jsx preserve or react-native
|
||||
let previousOnEmitNode: (emitContext: EmitContext, node: Node, emitCallback: (emitContext: EmitContext, node: Node) => void) => void;
|
||||
let noSubstitution: boolean[];
|
||||
if (compilerOptions.jsx === JsxEmit.Preserve) {
|
||||
if (compilerOptions.jsx === JsxEmit.Preserve || compilerOptions.jsx === JsxEmit.ReactNative) {
|
||||
previousOnEmitNode = context.onEmitNode;
|
||||
context.onEmitNode = onEmitNode;
|
||||
context.enableEmitNotification(SyntaxKind.JsxOpeningElement);
|
||||
@@ -116,4 +116,4 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-6
@@ -422,7 +422,7 @@
|
||||
LastBinaryOperator = CaretEqualsToken,
|
||||
FirstNode = QualifiedName,
|
||||
FirstJSDocNode = JSDocTypeExpression,
|
||||
LastJSDocNode = JSDocLiteralType,
|
||||
LastJSDocNode = JSDocNeverKeyword,
|
||||
FirstJSDocTagNode = JSDocComment,
|
||||
LastJSDocTagNode = JSDocNeverKeyword
|
||||
}
|
||||
@@ -2363,7 +2363,7 @@
|
||||
getIndexInfoOfType(type: Type, kind: IndexKind): IndexInfo;
|
||||
getSignaturesOfType(type: Type, kind: SignatureKind): Signature[];
|
||||
getIndexTypeOfType(type: Type, kind: IndexKind): Type;
|
||||
getBaseTypes(type: InterfaceType): ObjectType[];
|
||||
getBaseTypes(type: InterfaceType): BaseType[];
|
||||
getReturnTypeOfSignature(signature: Signature): Type;
|
||||
/**
|
||||
* Gets the type of a parameter at a given position in a signature.
|
||||
@@ -2718,6 +2718,7 @@
|
||||
containingType?: UnionOrIntersectionType; // Containing union or intersection type for synthetic property
|
||||
leftSpread?: Symbol; // Left source for synthetic spread property
|
||||
rightSpread?: Symbol; // Right source for synthetic spread property
|
||||
mappedTypeOrigin?: Symbol; // For a property on a mapped type, points back to the orignal 'T' from 'keyof T'.
|
||||
hasNonUniformType?: boolean; // True if constituents have non-uniform types
|
||||
isPartial?: boolean; // True if syntheric property of union type occurs in some but not all constituents
|
||||
isDiscriminantProperty?: boolean; // True if discriminant synthetic property
|
||||
@@ -2918,9 +2919,12 @@
|
||||
/* @internal */
|
||||
resolvedBaseConstructorType?: Type; // Resolved base constructor type of class
|
||||
/* @internal */
|
||||
resolvedBaseTypes: ObjectType[]; // Resolved base types
|
||||
resolvedBaseTypes: BaseType[]; // Resolved base types
|
||||
}
|
||||
|
||||
// Object type or intersection of object types
|
||||
export type BaseType = ObjectType | IntersectionType;
|
||||
|
||||
export interface InterfaceTypeWithDeclaredMembers extends InterfaceType {
|
||||
declaredProperties: Symbol[]; // Declared members
|
||||
declaredCallSignatures: Signature[]; // Declared call signatures
|
||||
@@ -2953,7 +2957,9 @@
|
||||
export interface UnionOrIntersectionType extends Type {
|
||||
types: Type[]; // Constituent types
|
||||
/* @internal */
|
||||
resolvedProperties: SymbolTable; // Cache of resolved properties
|
||||
propertyCache: SymbolTable; // Cache of resolved properties
|
||||
/* @internal */
|
||||
resolvedProperties: Symbol[];
|
||||
/* @internal */
|
||||
resolvedIndexType: IndexType;
|
||||
/* @internal */
|
||||
@@ -2964,7 +2970,10 @@
|
||||
|
||||
export interface UnionType extends UnionOrIntersectionType { }
|
||||
|
||||
export interface IntersectionType extends UnionOrIntersectionType { }
|
||||
export interface IntersectionType extends UnionOrIntersectionType {
|
||||
/* @internal */
|
||||
resolvedApparentType: Type;
|
||||
}
|
||||
|
||||
export type StructuredType = ObjectType | UnionType | IntersectionType;
|
||||
|
||||
@@ -3298,7 +3307,8 @@
|
||||
export const enum JsxEmit {
|
||||
None = 0,
|
||||
Preserve = 1,
|
||||
React = 2
|
||||
React = 2,
|
||||
ReactNative = 3
|
||||
}
|
||||
|
||||
export const enum NewLineKind {
|
||||
|
||||
+39
-139
@@ -2573,102 +2573,57 @@ namespace ts {
|
||||
* @param host An EmitHost.
|
||||
* @param targetSourceFile An optional target source file to emit.
|
||||
*/
|
||||
export function getSourceFilesToEmit(host: EmitHost, targetSourceFile?: SourceFile) {
|
||||
export function getSourceFilesToEmit(host: EmitHost, targetSourceFile?: SourceFile): SourceFile[] {
|
||||
const options = host.getCompilerOptions();
|
||||
const isSourceFileFromExternalLibrary = (file: SourceFile) => host.isSourceFileFromExternalLibrary(file);
|
||||
if (options.outFile || options.out) {
|
||||
const moduleKind = getEmitModuleKind(options);
|
||||
const moduleEmitEnabled = moduleKind === ModuleKind.AMD || moduleKind === ModuleKind.System;
|
||||
const sourceFiles = getAllEmittableSourceFiles();
|
||||
// Can emit only sources that are not declaration file and are either non module code or module with --module or --target es6 specified
|
||||
return filter(sourceFiles, moduleEmitEnabled ? isNonDeclarationFile : isBundleEmitNonExternalModule);
|
||||
return filter(host.getSourceFiles(), sourceFile =>
|
||||
(moduleEmitEnabled || !isExternalModule(sourceFile)) && sourceFileMayBeEmitted(sourceFile, options, isSourceFileFromExternalLibrary));
|
||||
}
|
||||
else {
|
||||
const sourceFiles = targetSourceFile === undefined ? getAllEmittableSourceFiles() : [targetSourceFile];
|
||||
return filterSourceFilesInDirectory(sourceFiles, file => host.isSourceFileFromExternalLibrary(file));
|
||||
}
|
||||
|
||||
function getAllEmittableSourceFiles() {
|
||||
return options.noEmitForJsFiles ? filter(host.getSourceFiles(), sourceFile => !isSourceFileJavaScript(sourceFile)) : host.getSourceFiles();
|
||||
const sourceFiles = targetSourceFile === undefined ? host.getSourceFiles() : [targetSourceFile];
|
||||
return filter(sourceFiles, sourceFile => sourceFileMayBeEmitted(sourceFile, options, isSourceFileFromExternalLibrary));
|
||||
}
|
||||
}
|
||||
|
||||
/** Don't call this for `--outFile`, just for `--outDir` or plain emit. */
|
||||
export function filterSourceFilesInDirectory(sourceFiles: SourceFile[], isSourceFileFromExternalLibrary: (file: SourceFile) => boolean): SourceFile[] {
|
||||
return filter(sourceFiles, file => shouldEmitInDirectory(file, isSourceFileFromExternalLibrary));
|
||||
}
|
||||
|
||||
function isNonDeclarationFile(sourceFile: SourceFile) {
|
||||
return !isDeclarationFile(sourceFile);
|
||||
/** Don't call this for `--outFile`, just for `--outDir` or plain emit. `--outFile` needs additional checks. */
|
||||
export function sourceFileMayBeEmitted(sourceFile: SourceFile, options: CompilerOptions, isSourceFileFromExternalLibrary: (file: SourceFile) => boolean) {
|
||||
return !(options.noEmitForJsFiles && isSourceFileJavaScript(sourceFile)) && !isDeclarationFile(sourceFile) && !isSourceFileFromExternalLibrary(sourceFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a file should be emitted in a non-`--outFile` case.
|
||||
* Don't emit if source file is a declaration file, or was located under node_modules
|
||||
*/
|
||||
function shouldEmitInDirectory(sourceFile: SourceFile, isSourceFileFromExternalLibrary: (file: SourceFile) => boolean): boolean {
|
||||
return isNonDeclarationFile(sourceFile) && !isSourceFileFromExternalLibrary(sourceFile);
|
||||
}
|
||||
|
||||
function isBundleEmitNonExternalModule(sourceFile: SourceFile) {
|
||||
return isNonDeclarationFile(sourceFile) && !isExternalModule(sourceFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over each source file to emit. The source files are expected to have been
|
||||
* transformed for use by the pretty printer.
|
||||
*
|
||||
* Originally part of `forEachExpectedEmitFile`, this functionality was extracted to support
|
||||
* transformations.
|
||||
* Iterates over the source files that are expected to have an emit output.
|
||||
*
|
||||
* @param host An EmitHost.
|
||||
* @param sourceFiles The transformed source files to emit.
|
||||
* @param action The action to execute.
|
||||
* @param sourceFilesOrTargetSourceFile
|
||||
* If an array, the full list of source files to emit.
|
||||
* Else, calls `getSourceFilesToEmit` with the (optional) target source file to determine the list of source files to emit.
|
||||
*/
|
||||
export function forEachTransformedEmitFile(host: EmitHost, sourceFiles: SourceFile[],
|
||||
action: (jsFilePath: string, sourceMapFilePath: string, declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean) => void,
|
||||
export function forEachEmittedFile(
|
||||
host: EmitHost, action: (emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean) => void,
|
||||
sourceFilesOrTargetSourceFile?: SourceFile[] | SourceFile,
|
||||
emitOnlyDtsFiles?: boolean) {
|
||||
|
||||
const sourceFiles = isArray(sourceFilesOrTargetSourceFile) ? sourceFilesOrTargetSourceFile : getSourceFilesToEmit(host, sourceFilesOrTargetSourceFile);
|
||||
const options = host.getCompilerOptions();
|
||||
// Emit on each source file
|
||||
if (options.outFile || options.out) {
|
||||
onBundledEmit(sourceFiles);
|
||||
}
|
||||
else {
|
||||
for (const sourceFile of sourceFiles) {
|
||||
// Don't emit if source file is a declaration file, or was located under node_modules
|
||||
if (!isDeclarationFile(sourceFile) && !host.isSourceFileFromExternalLibrary(sourceFile)) {
|
||||
onSingleFileEmit(host, sourceFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onSingleFileEmit(host: EmitHost, sourceFile: SourceFile) {
|
||||
// JavaScript files are always LanguageVariant.JSX, as JSX syntax is allowed in .js files also.
|
||||
// So for JavaScript files, '.jsx' is only emitted if the input was '.jsx', and JsxEmit.Preserve.
|
||||
// For TypeScript, the only time to emit with a '.jsx' extension, is on JSX input, and JsxEmit.Preserve
|
||||
let extension = ".js";
|
||||
if (options.jsx === JsxEmit.Preserve) {
|
||||
if (isSourceFileJavaScript(sourceFile)) {
|
||||
if (fileExtensionIs(sourceFile.fileName, ".jsx")) {
|
||||
extension = ".jsx";
|
||||
}
|
||||
}
|
||||
else if (sourceFile.languageVariant === LanguageVariant.JSX) {
|
||||
// TypeScript source file preserving JSX syntax
|
||||
extension = ".jsx";
|
||||
}
|
||||
}
|
||||
const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, extension);
|
||||
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
|
||||
const declarationFilePath = !isSourceFileJavaScript(sourceFile) && (options.declaration || emitOnlyDtsFiles) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
|
||||
action(jsFilePath, sourceMapFilePath, declarationFilePath, [sourceFile], /*isBundledEmit*/ false);
|
||||
}
|
||||
|
||||
function onBundledEmit(sourceFiles: SourceFile[]) {
|
||||
if (sourceFiles.length) {
|
||||
const jsFilePath = options.outFile || options.out;
|
||||
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
|
||||
const declarationFilePath = options.declaration ? removeFileExtension(jsFilePath) + ".d.ts" : undefined;
|
||||
action(jsFilePath, sourceMapFilePath, declarationFilePath, sourceFiles, /*isBundledEmit*/ true);
|
||||
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, sourceFiles, /*isBundledEmit*/true, emitOnlyDtsFiles);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const sourceFile of sourceFiles) {
|
||||
const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, getOutputExtension(sourceFile, options));
|
||||
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
|
||||
const declarationFilePath = !isSourceFileJavaScript(sourceFile) && (emitOnlyDtsFiles || options.declaration) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
|
||||
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, [sourceFile], /*isBundledEmit*/false, emitOnlyDtsFiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2677,77 +2632,22 @@ namespace ts {
|
||||
return options.sourceMap ? jsFilePath + ".map" : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the source files that are expected to have an emit output. This function
|
||||
* is used by the legacy emitter and the declaration emitter and should not be used by
|
||||
* the tree transforming emitter.
|
||||
*
|
||||
* @param host An EmitHost.
|
||||
* @param action The action to execute.
|
||||
* @param targetSourceFile An optional target source file to emit.
|
||||
*/
|
||||
export function forEachExpectedEmitFile(host: EmitHost,
|
||||
action: (emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean) => void,
|
||||
targetSourceFile?: SourceFile,
|
||||
emitOnlyDtsFiles?: boolean) {
|
||||
const options = host.getCompilerOptions();
|
||||
// Emit on each source file
|
||||
if (options.outFile || options.out) {
|
||||
onBundledEmit(host);
|
||||
}
|
||||
else {
|
||||
const sourceFiles = targetSourceFile === undefined ? getSourceFilesToEmit(host) : [targetSourceFile];
|
||||
for (const sourceFile of sourceFiles) {
|
||||
if (shouldEmitInDirectory(sourceFile, file => host.isSourceFileFromExternalLibrary(file))) {
|
||||
onSingleFileEmit(host, sourceFile);
|
||||
// JavaScript files are always LanguageVariant.JSX, as JSX syntax is allowed in .js files also.
|
||||
// So for JavaScript files, '.jsx' is only emitted if the input was '.jsx', and JsxEmit.Preserve.
|
||||
// For TypeScript, the only time to emit with a '.jsx' extension, is on JSX input, and JsxEmit.Preserve
|
||||
function getOutputExtension(sourceFile: SourceFile, options: CompilerOptions): string {
|
||||
if (options.jsx === JsxEmit.Preserve) {
|
||||
if (isSourceFileJavaScript(sourceFile)) {
|
||||
if (fileExtensionIs(sourceFile.fileName, ".jsx")) {
|
||||
return ".jsx";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function onSingleFileEmit(host: EmitHost, sourceFile: SourceFile) {
|
||||
// JavaScript files are always LanguageVariant.JSX, as JSX syntax is allowed in .js files also.
|
||||
// So for JavaScript files, '.jsx' is only emitted if the input was '.jsx', and JsxEmit.Preserve.
|
||||
// For TypeScript, the only time to emit with a '.jsx' extension, is on JSX input, and JsxEmit.Preserve
|
||||
let extension = ".js";
|
||||
if (options.jsx === JsxEmit.Preserve) {
|
||||
if (isSourceFileJavaScript(sourceFile)) {
|
||||
if (fileExtensionIs(sourceFile.fileName, ".jsx")) {
|
||||
extension = ".jsx";
|
||||
}
|
||||
}
|
||||
else if (sourceFile.languageVariant === LanguageVariant.JSX) {
|
||||
// TypeScript source file preserving JSX syntax
|
||||
extension = ".jsx";
|
||||
}
|
||||
}
|
||||
const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, extension);
|
||||
const declarationFilePath = !isSourceFileJavaScript(sourceFile) && (emitOnlyDtsFiles || options.declaration) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
|
||||
const emitFileNames: EmitFileNames = {
|
||||
jsFilePath,
|
||||
sourceMapFilePath: getSourceMapFilePath(jsFilePath, options),
|
||||
declarationFilePath
|
||||
};
|
||||
action(emitFileNames, [sourceFile], /*isBundledEmit*/false, emitOnlyDtsFiles);
|
||||
}
|
||||
|
||||
function onBundledEmit(host: EmitHost) {
|
||||
// Can emit only sources that are not declaration file and are either non module code or module with
|
||||
// --module or --target es6 specified. Files included by searching under node_modules are also not emitted.
|
||||
const bundledSources = filter(getSourceFilesToEmit(host),
|
||||
sourceFile => !isDeclarationFile(sourceFile) &&
|
||||
!host.isSourceFileFromExternalLibrary(sourceFile) &&
|
||||
(!isExternalModule(sourceFile) ||
|
||||
!!getEmitModuleKind(options)));
|
||||
if (bundledSources.length) {
|
||||
const jsFilePath = options.outFile || options.out;
|
||||
const emitFileNames: EmitFileNames = {
|
||||
jsFilePath,
|
||||
sourceMapFilePath: getSourceMapFilePath(jsFilePath, options),
|
||||
declarationFilePath: options.declaration ? removeFileExtension(jsFilePath) + ".d.ts" : undefined
|
||||
};
|
||||
action(emitFileNames, bundledSources, /*isBundledEmit*/true, emitOnlyDtsFiles);
|
||||
else if (sourceFile.languageVariant === LanguageVariant.JSX) {
|
||||
// TypeScript source file preserving JSX syntax
|
||||
return ".jsx";
|
||||
}
|
||||
}
|
||||
return ".js";
|
||||
}
|
||||
|
||||
export function getSourceFilePathInNewDir(sourceFile: SourceFile, host: EmitHost, newDirPath: string) {
|
||||
|
||||
@@ -372,8 +372,8 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
// Entry points from fourslash.ts
|
||||
public goToMarker(name = "") {
|
||||
const marker = this.getMarkerByName(name);
|
||||
public goToMarker(name: string | Marker = "") {
|
||||
const marker = typeof name === "string" ? this.getMarkerByName(name) : name;
|
||||
if (this.activeFile.fileName !== marker.fileName) {
|
||||
this.openFile(marker.fileName);
|
||||
}
|
||||
@@ -382,10 +382,37 @@ namespace FourSlash {
|
||||
if (marker.position === -1 || marker.position > content.length) {
|
||||
throw new Error(`Marker "${name}" has been invalidated by unrecoverable edits to the file.`);
|
||||
}
|
||||
this.lastKnownMarker = name;
|
||||
const mName = typeof name === "string" ? name : this.markerName(marker);
|
||||
this.lastKnownMarker = mName;
|
||||
this.goToPosition(marker.position);
|
||||
}
|
||||
|
||||
public goToEachMarker(action: () => void) {
|
||||
const markers = this.getMarkers();
|
||||
assert(markers.length);
|
||||
for (const marker of markers) {
|
||||
this.goToMarker(marker);
|
||||
action();
|
||||
}
|
||||
}
|
||||
|
||||
public goToEachRange(action: () => void) {
|
||||
const ranges = this.getRanges();
|
||||
assert(ranges.length);
|
||||
for (const range of ranges) {
|
||||
this.goToRangeStart(range);
|
||||
action();
|
||||
}
|
||||
}
|
||||
|
||||
private markerName(m: Marker): string {
|
||||
return ts.forEachEntry(this.testData.markerPositions, (marker, name) => {
|
||||
if (marker === m) {
|
||||
return name;
|
||||
}
|
||||
})!;
|
||||
}
|
||||
|
||||
public goToPosition(pos: number) {
|
||||
this.currentCaretPosition = pos;
|
||||
}
|
||||
@@ -1668,7 +1695,7 @@ namespace FourSlash {
|
||||
this.goToPosition(len);
|
||||
}
|
||||
|
||||
private goToRangeStart({fileName, start}: Range) {
|
||||
public goToRangeStart({fileName, start}: Range) {
|
||||
this.openFile(fileName);
|
||||
this.goToPosition(start);
|
||||
}
|
||||
@@ -2365,6 +2392,21 @@ namespace FourSlash {
|
||||
return this.languageService.getDocumentHighlights(this.activeFile.fileName, this.currentCaretPosition, filesToSearch);
|
||||
}
|
||||
|
||||
public verifyRangesAreOccurrences(isWriteAccess?: boolean) {
|
||||
const ranges = this.getRanges();
|
||||
for (const r of ranges) {
|
||||
this.goToRangeStart(r);
|
||||
this.verifyOccurrencesAtPositionListCount(ranges.length);
|
||||
for (const range of ranges) {
|
||||
this.verifyOccurrencesAtPositionListContains(range.fileName, range.start, range.end, isWriteAccess);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public verifyRangesAreRenameLocations(findInStrings: boolean, findInComments: boolean) {
|
||||
this.goToEachRange(() => this.verifyRenameLocations(findInStrings, findInComments));
|
||||
}
|
||||
|
||||
public verifyRangesWithSameTextAreDocumentHighlights() {
|
||||
this.rangesByText().forEach(ranges => this.verifyRangesAreDocumentHighlights(ranges));
|
||||
}
|
||||
@@ -3078,10 +3120,22 @@ namespace FourSlashInterface {
|
||||
// Moves the caret to the specified marker,
|
||||
// or the anonymous marker ('/**/') if no name
|
||||
// is given
|
||||
public marker(name?: string) {
|
||||
public marker(name?: string | FourSlash.Marker) {
|
||||
this.state.goToMarker(name);
|
||||
}
|
||||
|
||||
public eachMarker(action: () => void) {
|
||||
this.state.goToEachMarker(action);
|
||||
}
|
||||
|
||||
public rangeStart(range: FourSlash.Range) {
|
||||
this.state.goToRangeStart(range);
|
||||
}
|
||||
|
||||
public eachRange(action: () => void) {
|
||||
this.state.goToEachRange(action);
|
||||
}
|
||||
|
||||
public bof() {
|
||||
this.state.goToBOF();
|
||||
}
|
||||
@@ -3432,6 +3486,14 @@ namespace FourSlashInterface {
|
||||
this.state.verifyOccurrencesAtPositionListCount(expectedCount);
|
||||
}
|
||||
|
||||
public rangesAreOccurrences(isWriteAccess?: boolean) {
|
||||
this.state.verifyRangesAreOccurrences(isWriteAccess);
|
||||
}
|
||||
|
||||
public rangesAreRenameLocations(findInStrings = false, findInComments = false) {
|
||||
this.state.verifyRangesAreRenameLocations(findInStrings, findInComments);
|
||||
}
|
||||
|
||||
public rangesAreDocumentHighlights(ranges?: FourSlash.Range[]) {
|
||||
this.state.verifyRangesAreDocumentHighlights(ranges);
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace ts {
|
||||
start: undefined,
|
||||
length: undefined,
|
||||
}, {
|
||||
messageText: "Argument for '--jsx' option must be: 'preserve', 'react'",
|
||||
messageText: "Argument for '--jsx' option must be: 'preserve', 'react-native', 'react'",
|
||||
category: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.category,
|
||||
code: ts.Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ namespace ts {
|
||||
file: undefined,
|
||||
start: 0,
|
||||
length: 0,
|
||||
messageText: "Argument for '--jsx' option must be: 'preserve', 'react'",
|
||||
messageText: "Argument for '--jsx' option must be: 'preserve', 'react-native', 'react'",
|
||||
code: Diagnostics.Argument_for_0_option_must_be_Colon_1.code,
|
||||
category: Diagnostics.Argument_for_0_option_must_be_Colon_1.category
|
||||
}]
|
||||
|
||||
@@ -288,5 +288,24 @@ namespace ts {
|
||||
*/`);
|
||||
});
|
||||
});
|
||||
describe("getFirstToken", () => {
|
||||
it("gets jsdoc", () => {
|
||||
const root = ts.createSourceFile("foo.ts", "/** comment */var a = true;", ts.ScriptTarget.ES5, /*setParentNodes*/ true);
|
||||
assert.isDefined(root);
|
||||
assert.equal(root.kind, ts.SyntaxKind.SourceFile);
|
||||
const first = root.getFirstToken();
|
||||
assert.isDefined(first);
|
||||
assert.equal(first.kind, ts.SyntaxKind.VarKeyword);
|
||||
});
|
||||
});
|
||||
describe("getLastToken", () => {
|
||||
it("gets jsdoc", () => {
|
||||
const root = ts.createSourceFile("foo.ts", "var a = true;/** comment */", ts.ScriptTarget.ES5, /*setParentNodes*/ true);
|
||||
assert.isDefined(root);
|
||||
const last = root.getLastToken();
|
||||
assert.isDefined(last);
|
||||
assert.equal(last.kind, ts.SyntaxKind.EndOfFileToken);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -909,6 +909,31 @@ namespace ts {
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
});
|
||||
it("with jsx=react-native, allowJs=false", () => {
|
||||
const json = {
|
||||
compilerOptions: {
|
||||
jsx: "react-native",
|
||||
allowJs: false
|
||||
}
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {
|
||||
jsx: ts.JsxEmit.ReactNative,
|
||||
allowJs: false
|
||||
},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/a.ts",
|
||||
"c:/dev/b.tsx",
|
||||
"c:/dev/c.tsx",
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
});
|
||||
it("with jsx=none, allowJs=true", () => {
|
||||
const json = {
|
||||
compilerOptions: {
|
||||
@@ -961,6 +986,33 @@ namespace ts {
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
});
|
||||
it("with jsx=react-native, allowJs=true", () => {
|
||||
const json = {
|
||||
compilerOptions: {
|
||||
jsx: "react-native",
|
||||
allowJs: true
|
||||
}
|
||||
};
|
||||
const expected: ts.ParsedCommandLine = {
|
||||
options: {
|
||||
jsx: ts.JsxEmit.ReactNative,
|
||||
allowJs: true
|
||||
},
|
||||
errors: [],
|
||||
fileNames: [
|
||||
"c:/dev/a.ts",
|
||||
"c:/dev/b.tsx",
|
||||
"c:/dev/c.tsx",
|
||||
"c:/dev/d.js",
|
||||
"c:/dev/e.jsx",
|
||||
],
|
||||
wildcardDirectories: {
|
||||
"c:/dev": ts.WatchDirectoryFlags.Recursive
|
||||
}
|
||||
};
|
||||
const actual = ts.parseJsonConfigFileContent(json, caseInsensitiveMixedExtensionHost, caseInsensitiveBasePath);
|
||||
assertParsed(actual, expected);
|
||||
});
|
||||
it("exclude .min.js files using wildcards", () => {
|
||||
const json = {
|
||||
compilerOptions: {
|
||||
@@ -1306,4 +1358,4 @@ namespace ts {
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -4,7 +4,7 @@ interface Map<K, V> {
|
||||
forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void;
|
||||
get(key: K): V | undefined;
|
||||
has(key: K): boolean;
|
||||
set(key: K, value?: V): this;
|
||||
set(key: K, value: V): this;
|
||||
readonly size: number;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ interface WeakMap<K, V> {
|
||||
delete(key: K): boolean;
|
||||
get(key: K): V | undefined;
|
||||
has(key: K): boolean;
|
||||
set(key: K, value?: V): this;
|
||||
set(key: K, value: V): this;
|
||||
}
|
||||
|
||||
interface WeakMapConstructor {
|
||||
|
||||
Vendored
+1
-1
@@ -3,7 +3,7 @@ interface Symbol {
|
||||
toString(): string;
|
||||
|
||||
/** Returns the primitive value of the specified object. */
|
||||
valueOf(): Object;
|
||||
valueOf(): symbol;
|
||||
}
|
||||
|
||||
interface SymbolConstructor {
|
||||
|
||||
@@ -417,7 +417,7 @@ namespace ts.server.protocol {
|
||||
startOffset: number;
|
||||
|
||||
/**
|
||||
* Position (can be specified instead of line/offset pair)
|
||||
* Position (can be specified instead of line/offset pair)
|
||||
*/
|
||||
/* @internal */
|
||||
startPosition?: number;
|
||||
@@ -433,7 +433,7 @@ namespace ts.server.protocol {
|
||||
endOffset: number;
|
||||
|
||||
/**
|
||||
* Position (can be specified instead of line/offset pair)
|
||||
* Position (can be specified instead of line/offset pair)
|
||||
*/
|
||||
/* @internal */
|
||||
endPosition?: number;
|
||||
@@ -445,7 +445,7 @@ namespace ts.server.protocol {
|
||||
}
|
||||
|
||||
/**
|
||||
* Response for GetCodeFixes request.
|
||||
* Response for GetCodeFixes request.
|
||||
*/
|
||||
export interface GetCodeFixesResponse extends Response {
|
||||
body?: CodeAction[];
|
||||
@@ -2272,10 +2272,11 @@ namespace ts.server.protocol {
|
||||
export namespace JsxEmit {
|
||||
export type None = "None";
|
||||
export type Preserve = "Preserve";
|
||||
export type ReactNative = "ReactNative";
|
||||
export type React = "React";
|
||||
}
|
||||
|
||||
export type JsxEmit = JsxEmit.None | JsxEmit.Preserve | JsxEmit.React;
|
||||
export type JsxEmit = JsxEmit.None | JsxEmit.Preserve | JsxEmit.React | JsxEmit.ReactNative;
|
||||
|
||||
export namespace ModuleKind {
|
||||
export type None = "None";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* @internal */
|
||||
namespace ts.Completions {
|
||||
type Log = (message: string) => void;
|
||||
export type Log = (message: string) => void;
|
||||
|
||||
export function getCompletionsAtPosition(host: LanguageServiceHost, typeChecker: TypeChecker, log: Log, compilerOptions: CompilerOptions, sourceFile: SourceFile, position: number): CompletionInfo | undefined {
|
||||
if (isInReferenceComment(sourceFile, position)) {
|
||||
|
||||
@@ -17,25 +17,11 @@ namespace ts.DocumentHighlights {
|
||||
}
|
||||
|
||||
function getSemanticDocumentHighlights(node: Node, typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFilesToSearch: SourceFile[]): DocumentHighlights[] {
|
||||
if (node.kind === SyntaxKind.Identifier ||
|
||||
node.kind === SyntaxKind.ThisKeyword ||
|
||||
node.kind === SyntaxKind.ThisType ||
|
||||
node.kind === SyntaxKind.SuperKeyword ||
|
||||
node.kind === SyntaxKind.StringLiteral ||
|
||||
isLiteralNameOfPropertyDeclarationOrIndexAccess(node)) {
|
||||
|
||||
const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFilesToSearch, /*findInStrings*/ false, /*findInComments*/ false, /*implementations*/false);
|
||||
return convertReferencedSymbols(referencedSymbols);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
const referencedSymbols = FindAllReferences.getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFilesToSearch, /*findInStrings*/false, /*findInComments*/false, /*implementations*/false);
|
||||
return referencedSymbols && convertReferencedSymbols(referencedSymbols);
|
||||
}
|
||||
|
||||
function convertReferencedSymbols(referencedSymbols: ReferencedSymbol[]): DocumentHighlights[] {
|
||||
if (!referencedSymbols) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const fileNameToDocumentHighlights = createMap<DocumentHighlights>();
|
||||
const result: DocumentHighlights[] = [];
|
||||
for (const referencedSymbol of referencedSymbols) {
|
||||
|
||||
@@ -1,29 +1,16 @@
|
||||
/* @internal */
|
||||
namespace ts.FindAllReferences {
|
||||
export function findReferencedSymbols(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFiles: SourceFile[], sourceFile: SourceFile, position: number, findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] {
|
||||
export function findReferencedSymbols(typeChecker: TypeChecker, cancellationToken: CancellationToken, sourceFiles: SourceFile[], sourceFile: SourceFile, position: number, findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] | undefined {
|
||||
const node = getTouchingPropertyName(sourceFile, position, /*includeJsDocComment*/ true);
|
||||
if (node === sourceFile) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.NumericLiteral:
|
||||
if (!isLiteralNameOfPropertyDeclarationOrIndexAccess(node)) {
|
||||
break;
|
||||
}
|
||||
// Fallthrough
|
||||
case SyntaxKind.Identifier:
|
||||
case SyntaxKind.ThisKeyword:
|
||||
// case SyntaxKind.SuperKeyword: TODO:GH#9268
|
||||
case SyntaxKind.ConstructorKeyword:
|
||||
case SyntaxKind.StringLiteral:
|
||||
return getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFiles, findInStrings, findInComments, /*implementations*/false);
|
||||
}
|
||||
return undefined;
|
||||
return getReferencedSymbolsForNode(typeChecker, cancellationToken, node, sourceFiles, findInStrings, findInComments, /*implementations*/false);
|
||||
}
|
||||
|
||||
export function getReferencedSymbolsForNode(typeChecker: TypeChecker, cancellationToken: CancellationToken, node: Node, sourceFiles: SourceFile[], findInStrings: boolean, findInComments: boolean, implementations: boolean): ReferencedSymbol[] {
|
||||
export function getReferencedSymbolsForNode(typeChecker: TypeChecker, cancellationToken: CancellationToken, node: Node, sourceFiles: SourceFile[], findInStrings: boolean, findInComments: boolean, implementations: boolean): ReferencedSymbol[] | undefined {
|
||||
if (!implementations) {
|
||||
if (isTypeKeyword(node.kind)) {
|
||||
return getAllReferencesForKeyword(sourceFiles, node.kind, cancellationToken);
|
||||
}
|
||||
|
||||
// Labels
|
||||
if (isLabelName(node)) {
|
||||
if (isJumpStatementTarget(node)) {
|
||||
@@ -68,8 +55,6 @@ namespace ts.FindAllReferences {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let result: ReferencedSymbol[];
|
||||
|
||||
// Compute the meaning from the location and the symbol it references
|
||||
const searchMeaning = getIntersectingMeaningFromDeclarations(getMeaningFromLocation(node), declarations);
|
||||
|
||||
@@ -84,6 +69,7 @@ namespace ts.FindAllReferences {
|
||||
// Maps from a symbol ID to the ReferencedSymbol entry in 'result'.
|
||||
const symbolToIndex: number[] = [];
|
||||
|
||||
let result: ReferencedSymbol[];
|
||||
if (scope) {
|
||||
result = [];
|
||||
getReferencesInNode(scope, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex, implementations, typeChecker, cancellationToken);
|
||||
@@ -92,10 +78,7 @@ namespace ts.FindAllReferences {
|
||||
const internedName = getInternedName(symbol, node);
|
||||
for (const sourceFile of sourceFiles) {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
const nameTable = getNameTable(sourceFile);
|
||||
|
||||
if (nameTable.get(internedName) !== undefined) {
|
||||
if (sourceFileHasName(sourceFile, internedName)) {
|
||||
result = result || [];
|
||||
getReferencesInNode(sourceFile, symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result, symbolToIndex, implementations, typeChecker, cancellationToken);
|
||||
}
|
||||
@@ -105,9 +88,13 @@ namespace ts.FindAllReferences {
|
||||
return result;
|
||||
}
|
||||
|
||||
function sourceFileHasName(sourceFile: SourceFile, name: string): boolean {
|
||||
return getNameTable(sourceFile).get(name) !== undefined;
|
||||
}
|
||||
|
||||
function getDefinition(symbol: Symbol, node: Node, typeChecker: TypeChecker): ReferencedSymbolDefinitionInfo {
|
||||
const info = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, node.getSourceFile(), getContainerNode(node), node);
|
||||
const name = map(info.displayParts, p => p.text).join("");
|
||||
const { displayParts, symbolKind } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, node.getSourceFile(), getContainerNode(node), node);
|
||||
const name = displayParts.map(p => p.text).join("");
|
||||
const declarations = symbol.declarations;
|
||||
if (!declarations || declarations.length === 0) {
|
||||
return undefined;
|
||||
@@ -117,10 +104,10 @@ namespace ts.FindAllReferences {
|
||||
containerKind: "",
|
||||
containerName: "",
|
||||
name,
|
||||
kind: info.symbolKind,
|
||||
kind: symbolKind,
|
||||
fileName: declarations[0].getSourceFile().fileName,
|
||||
textSpan: createTextSpan(declarations[0].getStart(), 0),
|
||||
displayParts: info.displayParts
|
||||
displayParts
|
||||
};
|
||||
}
|
||||
|
||||
@@ -351,6 +338,43 @@ namespace ts.FindAllReferences {
|
||||
}
|
||||
}
|
||||
|
||||
function getAllReferencesForKeyword(sourceFiles: SourceFile[], keywordKind: ts.SyntaxKind, cancellationToken: CancellationToken): ReferencedSymbol[] {
|
||||
const name = tokenToString(keywordKind);
|
||||
const definition: ReferencedSymbolDefinitionInfo = {
|
||||
containerKind: "",
|
||||
containerName: "",
|
||||
fileName: "",
|
||||
kind: ScriptElementKind.keyword,
|
||||
name,
|
||||
textSpan: createTextSpan(0, 1),
|
||||
displayParts: [{ text: name, kind: ScriptElementKind.keyword }]
|
||||
}
|
||||
|
||||
const references: ReferenceEntry[] = [];
|
||||
for (const sourceFile of sourceFiles) {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
addReferencesForKeywordInFile(sourceFile, keywordKind, name, cancellationToken, references);
|
||||
}
|
||||
|
||||
return [{ definition, references }];
|
||||
}
|
||||
|
||||
function addReferencesForKeywordInFile(sourceFile: SourceFile, kind: SyntaxKind, searchText: string, cancellationToken: CancellationToken, references: Push<ReferenceEntry>): void {
|
||||
const possiblePositions = getPossibleSymbolReferencePositions(sourceFile, searchText, sourceFile.getStart(), sourceFile.getEnd(), cancellationToken);
|
||||
for (const position of possiblePositions) {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
const referenceLocation = getTouchingPropertyName(sourceFile, position);
|
||||
if (referenceLocation.kind === kind) {
|
||||
references.push({
|
||||
textSpan: createTextSpanFromNode(referenceLocation),
|
||||
fileName: sourceFile.fileName,
|
||||
isWriteAccess: false,
|
||||
isDefinition: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Search within node "container" for references for a search value, where the search value is defined as a
|
||||
* tuple of(searchSymbol, searchText, searchLocation, and searchMeaning).
|
||||
* searchLocation: a node where the search value
|
||||
@@ -375,67 +399,64 @@ namespace ts.FindAllReferences {
|
||||
|
||||
const parents = getParentSymbolsOfPropertyAccess();
|
||||
const inheritsFromCache: Map<boolean> = createMap<boolean>();
|
||||
// Build the set of symbols to search for, initially it has only the current symbol
|
||||
const searchSymbols = populateSearchSymbolSet(searchSymbol, searchLocation, typeChecker, implementations);
|
||||
|
||||
if (possiblePositions.length) {
|
||||
// Build the set of symbols to search for, initially it has only the current symbol
|
||||
const searchSymbols = populateSearchSymbolSet(searchSymbol, searchLocation, typeChecker, implementations);
|
||||
for (const position of possiblePositions) {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
|
||||
forEach(possiblePositions, position => {
|
||||
cancellationToken.throwIfCancellationRequested();
|
||||
const referenceLocation = getTouchingPropertyName(sourceFile, position);
|
||||
if (!isValidReferencePosition(referenceLocation, searchText)) {
|
||||
// This wasn't the start of a token. Check to see if it might be a
|
||||
// match in a comment or string if that's what the caller is asking
|
||||
// for.
|
||||
if (!implementations && ((findInStrings && isInString(sourceFile, position)) ||
|
||||
(findInComments && isInNonReferenceComment(sourceFile, position)))) {
|
||||
|
||||
const referenceLocation = getTouchingPropertyName(sourceFile, position);
|
||||
if (!isValidReferencePosition(referenceLocation, searchText)) {
|
||||
// This wasn't the start of a token. Check to see if it might be a
|
||||
// match in a comment or string if that's what the caller is asking
|
||||
// for.
|
||||
if (!implementations && ((findInStrings && isInString(sourceFile, position)) ||
|
||||
(findInComments && isInNonReferenceComment(sourceFile, position)))) {
|
||||
|
||||
// In the case where we're looking inside comments/strings, we don't have
|
||||
// an actual definition. So just use 'undefined' here. Features like
|
||||
// 'Rename' won't care (as they ignore the definitions), and features like
|
||||
// 'FindReferences' will just filter out these results.
|
||||
result.push({
|
||||
definition: undefined,
|
||||
references: [{
|
||||
fileName: sourceFile.fileName,
|
||||
textSpan: createTextSpan(position, searchText.length),
|
||||
isWriteAccess: false,
|
||||
isDefinition: false
|
||||
}]
|
||||
});
|
||||
}
|
||||
return;
|
||||
// In the case where we're looking inside comments/strings, we don't have
|
||||
// an actual definition. So just use 'undefined' here. Features like
|
||||
// 'Rename' won't care (as they ignore the definitions), and features like
|
||||
// 'FindReferences' will just filter out these results.
|
||||
result.push({
|
||||
definition: undefined,
|
||||
references: [{
|
||||
fileName: sourceFile.fileName,
|
||||
textSpan: createTextSpan(position, searchText.length),
|
||||
isWriteAccess: false,
|
||||
isDefinition: false
|
||||
}]
|
||||
});
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(getMeaningFromLocation(referenceLocation) & searchMeaning)) {
|
||||
return;
|
||||
if (!(getMeaningFromLocation(referenceLocation) & searchMeaning)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const referenceSymbol = typeChecker.getSymbolAtLocation(referenceLocation);
|
||||
if (referenceSymbol) {
|
||||
const referenceSymbolDeclaration = referenceSymbol.valueDeclaration;
|
||||
const shorthandValueSymbol = typeChecker.getShorthandAssignmentValueSymbol(referenceSymbolDeclaration);
|
||||
const relatedSymbol = getRelatedSymbol(searchSymbols, referenceSymbol, referenceLocation,
|
||||
/*searchLocationIsConstructor*/ searchLocation.kind === SyntaxKind.ConstructorKeyword, parents, inheritsFromCache, typeChecker);
|
||||
|
||||
if (relatedSymbol) {
|
||||
addReferenceToRelatedSymbol(referenceLocation, relatedSymbol);
|
||||
}
|
||||
|
||||
const referenceSymbol = typeChecker.getSymbolAtLocation(referenceLocation);
|
||||
if (referenceSymbol) {
|
||||
const referenceSymbolDeclaration = referenceSymbol.valueDeclaration;
|
||||
const shorthandValueSymbol = typeChecker.getShorthandAssignmentValueSymbol(referenceSymbolDeclaration);
|
||||
const relatedSymbol = getRelatedSymbol(searchSymbols, referenceSymbol, referenceLocation,
|
||||
/*searchLocationIsConstructor*/ searchLocation.kind === SyntaxKind.ConstructorKeyword, parents, inheritsFromCache, typeChecker);
|
||||
|
||||
if (relatedSymbol) {
|
||||
addReferenceToRelatedSymbol(referenceLocation, relatedSymbol);
|
||||
}
|
||||
/* Because in short-hand property assignment, an identifier which stored as name of the short-hand property assignment
|
||||
* has two meaning : property name and property value. Therefore when we do findAllReference at the position where
|
||||
* an identifier is declared, the language service should return the position of the variable declaration as well as
|
||||
* the position in short-hand property assignment excluding property accessing. However, if we do findAllReference at the
|
||||
* position of property accessing, the referenceEntry of such position will be handled in the first case.
|
||||
*/
|
||||
else if (!(referenceSymbol.flags & SymbolFlags.Transient) && searchSymbols.indexOf(shorthandValueSymbol) >= 0) {
|
||||
addReferenceToRelatedSymbol(referenceSymbolDeclaration.name, shorthandValueSymbol);
|
||||
}
|
||||
else if (searchLocation.kind === SyntaxKind.ConstructorKeyword) {
|
||||
findAdditionalConstructorReferences(referenceSymbol, referenceLocation);
|
||||
}
|
||||
/* Because in short-hand property assignment, an identifier which stored as name of the short-hand property assignment
|
||||
* has two meaning : property name and property value. Therefore when we do findAllReference at the position where
|
||||
* an identifier is declared, the language service should return the position of the variable declaration as well as
|
||||
* the position in short-hand property assignment excluding property accessing. However, if we do findAllReference at the
|
||||
* position of property accessing, the referenceEntry of such position will be handled in the first case.
|
||||
*/
|
||||
else if (!(referenceSymbol.flags & SymbolFlags.Transient) && searchSymbols.indexOf(shorthandValueSymbol) >= 0) {
|
||||
addReferenceToRelatedSymbol(referenceSymbolDeclaration.name, shorthandValueSymbol);
|
||||
}
|
||||
});
|
||||
else if (searchLocation.kind === SyntaxKind.ConstructorKeyword) {
|
||||
findAdditionalConstructorReferences(referenceSymbol, referenceLocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
|
||||
+12
-11
@@ -193,9 +193,10 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const child = children[0];
|
||||
|
||||
return child.kind < SyntaxKind.FirstNode ? child : child.getFirstToken(sourceFile);
|
||||
const child = ts.find(children, kid => kid.kind < SyntaxKind.FirstJSDocNode || kid.kind > SyntaxKind.LastJSDocNode);
|
||||
return child.kind < SyntaxKind.FirstNode ?
|
||||
child :
|
||||
child.getFirstToken(sourceFile);
|
||||
}
|
||||
|
||||
public getLastToken(sourceFile?: SourceFile): Node {
|
||||
@@ -379,7 +380,7 @@ namespace ts {
|
||||
getNumberIndexType(): Type {
|
||||
return this.checker.getIndexTypeOfType(this, IndexKind.Number);
|
||||
}
|
||||
getBaseTypes(): ObjectType[] {
|
||||
getBaseTypes(): BaseType[] {
|
||||
return this.flags & TypeFlags.Object && this.objectFlags & (ObjectFlags.Class | ObjectFlags.Interface)
|
||||
? this.checker.getBaseTypes(<InterfaceType><Type>this)
|
||||
: undefined;
|
||||
@@ -1959,11 +1960,9 @@ namespace ts {
|
||||
|
||||
function walk(node: Node) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Identifier: {
|
||||
const text = (<Identifier>node).text;
|
||||
nameTable.set(text, nameTable.get(text) === undefined ? node.pos : -1);
|
||||
case SyntaxKind.Identifier:
|
||||
setNameTable((<Identifier>node).text, node);
|
||||
break;
|
||||
}
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
// We want to store any numbers/strings if they were a name that could be
|
||||
@@ -1974,9 +1973,7 @@ namespace ts {
|
||||
node.parent.kind === SyntaxKind.ExternalModuleReference ||
|
||||
isArgumentOfElementAccessExpression(node) ||
|
||||
isLiteralComputedPropertyDeclarationName(node)) {
|
||||
|
||||
const text = (<LiteralExpression>node).text;
|
||||
nameTable.set(text, nameTable.get(text) === undefined ? node.pos : -1);
|
||||
setNameTable((<LiteralExpression>node).text, node);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -1988,6 +1985,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setNameTable(text: string, node: ts.Node): void {
|
||||
nameTable.set(text, nameTable.get(text) === undefined ? node.pos : -1);
|
||||
}
|
||||
}
|
||||
|
||||
function isObjectLiteralElement(node: Node): node is ObjectLiteralElement {
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace ts {
|
||||
getConstructSignatures(): Signature[];
|
||||
getStringIndexType(): Type;
|
||||
getNumberIndexType(): Type;
|
||||
getBaseTypes(): ObjectType[];
|
||||
getBaseTypes(): BaseType[];
|
||||
getNonNullableType(): Type;
|
||||
}
|
||||
|
||||
@@ -495,7 +495,7 @@ namespace ts {
|
||||
|
||||
export interface SymbolDisplayPart {
|
||||
text: string;
|
||||
kind: string;
|
||||
kind: string; // A ScriptElementKind
|
||||
}
|
||||
|
||||
export interface QuickInfo {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// These utilities are common to multiple language service features.
|
||||
// These utilities are common to multiple language service features.
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export const scanner: Scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true);
|
||||
@@ -72,7 +72,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function getMeaningFromLocation(node: Node): SemanticMeaning {
|
||||
if (node.parent.kind === SyntaxKind.ExportAssignment) {
|
||||
if (node.kind === SyntaxKind.SourceFile) {
|
||||
return SemanticMeaning.Value;
|
||||
}
|
||||
else if (node.parent.kind === SyntaxKind.ExportAssignment) {
|
||||
return SemanticMeaning.Value | SemanticMeaning.Type | SemanticMeaning.Namespace;
|
||||
}
|
||||
else if (isInRightSideOfImport(node)) {
|
||||
@@ -1117,6 +1120,22 @@ namespace ts {
|
||||
export function createTextSpanFromNode(node: Node, sourceFile?: SourceFile): TextSpan {
|
||||
return createTextSpanFromBounds(node.getStart(sourceFile), node.getEnd());
|
||||
}
|
||||
|
||||
export function isTypeKeyword(kind: SyntaxKind): boolean {
|
||||
switch (kind) {
|
||||
case SyntaxKind.AnyKeyword:
|
||||
case SyntaxKind.BooleanKeyword:
|
||||
case SyntaxKind.NeverKeyword:
|
||||
case SyntaxKind.NumberKeyword:
|
||||
case SyntaxKind.ObjectKeyword:
|
||||
case SyntaxKind.StringKeyword:
|
||||
case SyntaxKind.SymbolKeyword:
|
||||
case SyntaxKind.VoidKeyword:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Display-part writer helpers
|
||||
|
||||
Reference in New Issue
Block a user