Merge branch 'master' into codefix_add_missing_new_operator

This commit is contained in:
iliashkolyar
2018-09-19 00:06:39 +03:00
committed by GitHub
210 changed files with 20971 additions and 15707 deletions
+1
View File
@@ -75,6 +75,7 @@
"gulp-typescript": "latest",
"istanbul": "latest",
"jake": "latest",
"lodash": "4.17.10",
"merge2": "latest",
"minimist": "latest",
"mkdirp": "latest",
+2 -2
View File
@@ -2465,7 +2465,7 @@ namespace ts {
node.left.parent = node;
node.right.parent = node;
const lhs = node.left as PropertyAccessEntityNameExpression;
bindPropertyAssignment(lhs, lhs, /*isPrototypeProperty*/ false);
bindPropertyAssignment(lhs.expression, lhs, /*isPrototypeProperty*/ false);
}
/**
@@ -2522,7 +2522,7 @@ namespace ts {
const isToplevel = isBinaryExpression(propertyAccess.parent)
? getParentOfBinaryExpression(propertyAccess.parent).parent.kind === SyntaxKind.SourceFile
: propertyAccess.parent.parent.kind === SyntaxKind.SourceFile;
if (!isPrototypeProperty && (!namespaceSymbol || !(namespaceSymbol.flags & SymbolFlags.Namespace)) && isToplevel) {
if (isToplevel && !isPrototypeProperty && (!namespaceSymbol || !(namespaceSymbol.flags & SymbolFlags.Namespace))) {
// make symbols or add declarations for intermediate containers
const flags = SymbolFlags.Module | SymbolFlags.Assignment;
const excludeFlags = SymbolFlags.ValueModuleExcludes & ~SymbolFlags.Assignment;
+10 -3
View File
@@ -88,7 +88,7 @@ namespace ts.BuilderState {
function getReferencedFileFromImportedModuleSymbol(symbol: Symbol) {
if (symbol.declarations && symbol.declarations[0]) {
const declarationSourceFile = getSourceFileOfNode(symbol.declarations[0]);
return declarationSourceFile && declarationSourceFile.path;
return declarationSourceFile && (declarationSourceFile.resolvedPath || declarationSourceFile.path);
}
}
@@ -100,6 +100,13 @@ namespace ts.BuilderState {
return symbol && getReferencedFileFromImportedModuleSymbol(symbol);
}
/**
* Gets the path to reference file from file name, it could be resolvedPath if present otherwise path
*/
function getReferencedFileFromFileName(program: Program, fileName: string, sourceFileDirectory: Path, getCanonicalFileName: GetCanonicalFileName): Path {
return toPath(program.getProjectReferenceRedirect(fileName) || fileName, sourceFileDirectory, getCanonicalFileName);
}
/**
* Gets the referenced files for a file from the program with values for the keys as referenced file's path to be true
*/
@@ -123,7 +130,7 @@ namespace ts.BuilderState {
// Handle triple slash references
if (sourceFile.referencedFiles && sourceFile.referencedFiles.length > 0) {
for (const referencedFile of sourceFile.referencedFiles) {
const referencedPath = toPath(referencedFile.fileName, sourceFileDirectory, getCanonicalFileName);
const referencedPath = getReferencedFileFromFileName(program, referencedFile.fileName, sourceFileDirectory, getCanonicalFileName);
addReferencedFile(referencedPath);
}
}
@@ -136,7 +143,7 @@ namespace ts.BuilderState {
}
const fileName = resolvedTypeReferenceDirective.resolvedFileName!; // TODO: GH#18217
const typeFilePath = toPath(fileName, sourceFileDirectory, getCanonicalFileName);
const typeFilePath = getReferencedFileFromFileName(program, fileName, sourceFileDirectory, getCanonicalFileName);
addReferencedFile(typeFilePath);
});
}
+149 -57
View File
@@ -601,6 +601,8 @@ namespace ts {
FunctionFacts = FunctionStrictFacts | EQUndefined | EQNull | EQUndefinedOrNull | Falsy,
UndefinedFacts = TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEObject | TypeofNEFunction | TypeofNEHostObject | EQUndefined | EQUndefinedOrNull | NENull | Falsy,
NullFacts = TypeofEQObject | TypeofNEString | TypeofNENumber | TypeofNEBoolean | TypeofNESymbol | TypeofNEFunction | TypeofNEHostObject | EQNull | EQUndefinedOrNull | NEUndefined | Falsy,
EmptyObjectStrictFacts = All & ~(EQUndefined | EQNull | EQUndefinedOrNull),
EmptyObjectFacts = All,
}
const typeofEQFacts = createMapFromTemplate({
@@ -640,7 +642,7 @@ namespace ts {
const identityRelation = createMap<RelationComparisonResult>();
const enumRelation = createMap<RelationComparisonResult>();
type TypeSystemEntity = Symbol | Type | Signature;
type TypeSystemEntity = Node | Symbol | Type | Signature;
const enum TypeSystemPropertyName {
Type,
@@ -648,6 +650,7 @@ namespace ts {
DeclaredType,
ResolvedReturnType,
ImmediateBaseConstraint,
EnumTagType,
}
const enum CheckMode {
@@ -3470,8 +3473,8 @@ namespace ts {
const arity = getTypeReferenceArity(type);
const tupleConstituentNodes = mapToTypeNodes(typeArguments.slice(0, arity), context);
const hasRestElement = (<TupleType>type.target).hasRestElement;
if (tupleConstituentNodes && tupleConstituentNodes.length > 0) {
for (let i = (<TupleType>type.target).minLength; i < arity; i++) {
if (tupleConstituentNodes) {
for (let i = (<TupleType>type.target).minLength; i < Math.min(arity, tupleConstituentNodes.length); i++) {
tupleConstituentNodes[i] = hasRestElement && i === arity - 1 ?
createRestTypeNode(createArrayTypeNode(tupleConstituentNodes[i])) :
createOptionalTypeNode(tupleConstituentNodes[i]);
@@ -4475,6 +4478,8 @@ namespace ts {
switch (propertyName) {
case TypeSystemPropertyName.Type:
return !!getSymbolLinks(<Symbol>target).type;
case TypeSystemPropertyName.EnumTagType:
return !!(getNodeLinks(target as JSDocEnumTag).resolvedEnumType);
case TypeSystemPropertyName.DeclaredType:
return !!getSymbolLinks(<Symbol>target).declaredType;
case TypeSystemPropertyName.ResolvedBaseConstructorType:
@@ -8252,9 +8257,18 @@ namespace ts {
}
// JS are 'string' or 'number', not an enum type.
const enumTag = symbol.valueDeclaration && getJSDocEnumTag(symbol.valueDeclaration);
const enumTag = isInJSFile(node) && symbol.valueDeclaration && getJSDocEnumTag(symbol.valueDeclaration);
if (enumTag) {
return enumTag.typeExpression ? getTypeFromTypeNode(enumTag.typeExpression) : errorType;
const links = getNodeLinks(enumTag);
if (!pushTypeResolution(enumTag, TypeSystemPropertyName.EnumTagType)) {
return errorType;
}
let type = enumTag.typeExpression ? getTypeFromTypeNode(enumTag.typeExpression) : errorType;
if (!popTypeResolution()) {
type = errorType;
error(node, Diagnostics.Enum_type_0_circularly_references_itself, symbolToString(symbol));
}
return (links.resolvedEnumType = type);
}
// Get type from reference to named type that cannot be generic (enum or type parameter)
@@ -10624,6 +10638,8 @@ namespace ts {
return elaborateArrayLiteral(node as ArrayLiteralExpression, source, target, relation);
case SyntaxKind.JsxAttributes:
return elaborateJsxAttributes(node as JsxAttributes, source, target, relation);
case SyntaxKind.ArrowFunction:
return elaborateArrowFunction(node as ArrowFunction, source, target, relation);
}
return false;
}
@@ -10649,6 +10665,46 @@ namespace ts {
return false;
}
function elaborateArrowFunction(node: ArrowFunction, source: Type, target: Type, relation: Map<RelationComparisonResult>): boolean {
// Don't elaborate blocks
if (isBlock(node.body)) {
return false;
}
// Or functions with annotated parameter types
if (some(node.parameters, ts.hasType)) {
return false;
}
const sourceSig = getSingleCallSignature(source);
if (!sourceSig) {
return false;
}
const targetSignatures = getSignaturesOfType(target, SignatureKind.Call);
if (!length(targetSignatures)) {
return false;
}
const returnExpression = node.body;
const sourceReturn = getReturnTypeOfSignature(sourceSig);
const targetReturn = getUnionType(map(targetSignatures, getReturnTypeOfSignature));
if (!checkTypeRelatedTo(sourceReturn, targetReturn, relation, /*errorNode*/ undefined)) {
const elaborated = returnExpression && elaborateError(returnExpression, sourceReturn, targetReturn, relation, /*headMessage*/ undefined);
if (elaborated) {
return elaborated;
}
const resultObj: { error?: Diagnostic } = {};
checkTypeRelatedTo(sourceReturn, targetReturn, relation, returnExpression, /*message*/ undefined, /*chain*/ undefined, resultObj);
if (resultObj.error) {
if (target.symbol && length(target.symbol.declarations)) {
addRelatedInfo(resultObj.error, createDiagnosticForNode(
target.symbol.declarations[0],
Diagnostics.The_expected_type_comes_from_the_return_type_of_this_signature,
));
}
return true;
}
}
return false;
}
type ElaborationIterator = IterableIterator<{ errorNode: Node, innerExpression: Expression | undefined, nameType: Type, errorMessage?: DiagnosticMessage | undefined }>;
/**
* For every element returned from the iterator, checks that element to issue an error on a property of that element's type
@@ -10662,7 +10718,7 @@ namespace ts {
const { errorNode: prop, innerExpression: next, nameType, errorMessage } = status.value;
const sourcePropType = getIndexedAccessType(source, nameType, /*accessNode*/ undefined, errorType);
const targetPropType = getIndexedAccessType(target, nameType, /*accessNode*/ undefined, errorType);
if (sourcePropType !== errorType && targetPropType !== errorType && !isTypeAssignableTo(sourcePropType, targetPropType)) {
if (sourcePropType !== errorType && targetPropType !== errorType && !checkTypeRelatedTo(sourcePropType, targetPropType, relation, /*errorNode*/ undefined)) {
const elaborated = next && elaborateError(next, sourcePropType, targetPropType, relation, /*headMessage*/ undefined);
if (elaborated) {
reportedError = true;
@@ -10687,19 +10743,22 @@ namespace ts {
const indexInfo = isTypeAssignableToKind(nameType, TypeFlags.NumberLike) && getIndexInfoOfType(target, IndexKind.Number) ||
getIndexInfoOfType(target, IndexKind.String) ||
undefined;
if (indexInfo && indexInfo.declaration) {
if (indexInfo && indexInfo.declaration && !getSourceFileOfNode(indexInfo.declaration).hasNoDefaultLib) {
issuedElaboration = true;
addRelatedInfo(reportedDiag, createDiagnosticForNode(indexInfo.declaration, Diagnostics.The_expected_type_comes_from_this_index_signature));
}
}
if (!issuedElaboration && (targetProp && length(targetProp.declarations) || target.symbol && length(target.symbol.declarations))) {
addRelatedInfo(reportedDiag, createDiagnosticForNode(
targetProp && length(targetProp.declarations) ? targetProp.declarations[0] : target.symbol.declarations[0],
Diagnostics.The_expected_type_comes_from_property_0_which_is_declared_here_on_type_1,
propertyName && !(nameType.flags & TypeFlags.UniqueESSymbol) ? unescapeLeadingUnderscores(propertyName) : typeToString(nameType),
typeToString(target)
));
const targetNode = targetProp && length(targetProp.declarations) ? targetProp.declarations[0] : target.symbol.declarations[0];
if (!getSourceFileOfNode(targetNode).hasNoDefaultLib) {
addRelatedInfo(reportedDiag, createDiagnosticForNode(
targetNode,
Diagnostics.The_expected_type_comes_from_property_0_which_is_declared_here_on_type_1,
propertyName && !(nameType.flags & TypeFlags.UniqueESSymbol) ? unescapeLeadingUnderscores(propertyName) : typeToString(nameType),
typeToString(target)
));
}
}
}
reportedError = true;
@@ -10738,6 +10797,11 @@ namespace ts {
if (isTupleLikeType(source)) {
return elaborateElementwise(generateLimitedTupleElements(node, target), source, target, relation);
}
// recreate a tuple from the elements, if possible
const tupleizedType = checkArrayLiteral(node, CheckMode.Contextual, /*forceTuple*/ true);
if (isTupleLikeType(tupleizedType)) {
return elaborateElementwise(generateLimitedTupleElements(node, target), tupleizedType, target, relation);
}
return false;
}
@@ -11774,8 +11838,12 @@ namespace ts {
const simplified = getSimplifiedType((<IndexType>target).type);
const constraint = simplified !== (<IndexType>target).type ? simplified : getConstraintOfType((<IndexType>target).type);
if (constraint) {
if (result = isRelatedTo(source, getIndexType(constraint, (target as IndexType).stringsOnly), reportErrors)) {
return result;
// We require Ternary.True here such that circular constraints don't cause
// false positives. For example, given 'T extends { [K in keyof T]: string }',
// 'keyof T' has itself as its constraint and produces a Ternary.Maybe when
// related to other types.
if (isRelatedTo(source, getIndexType(constraint, (target as IndexType).stringsOnly), reportErrors) === Ternary.True) {
return Ternary.True;
}
}
}
@@ -13373,7 +13441,7 @@ namespace ts {
let propagationType: Type;
inferFromTypes(originalSource, originalTarget);
function inferFromTypes(source: Type, target: Type) {
function inferFromTypes(source: Type, target: Type): void {
if (!couldContainTypeVariables(target)) {
return;
}
@@ -13508,6 +13576,9 @@ namespace ts {
inferFromTypes(getTrueTypeFromConditionalType(<ConditionalType>source), getTrueTypeFromConditionalType(<ConditionalType>target));
inferFromTypes(getFalseTypeFromConditionalType(<ConditionalType>source), getFalseTypeFromConditionalType(<ConditionalType>target));
}
else if (target.flags & TypeFlags.Conditional) {
inferFromTypes(source, getUnionType([getTrueTypeFromConditionalType(<ConditionalType>target), getFalseTypeFromConditionalType(<ConditionalType>target)]));
}
else if (target.flags & TypeFlags.UnionOrIntersection) {
const targetTypes = (<UnionOrIntersectionType>target).types;
let typeVariableCount = 0;
@@ -13541,7 +13612,14 @@ namespace ts {
}
else {
if (!(priority & InferencePriority.NoConstraints && source.flags & (TypeFlags.Intersection | TypeFlags.Instantiable))) {
source = getApparentType(source);
const apparentSource = getApparentType(source);
// getApparentType can return _any_ type, since an indexed access or conditional may simplify to any other type.
// If that occurs and it doesn't simplify to an object or intersection, we'll need to restart `inferFromTypes`
// with the simplified source.
if (apparentSource !== source && !(apparentSource.flags & (TypeFlags.Object | TypeFlags.Intersection))) {
return inferFromTypes(apparentSource, target);
}
source = apparentSource;
}
if (source.flags & (TypeFlags.Object | TypeFlags.Intersection)) {
const key = source.id + "," + target.id;
@@ -13747,7 +13825,7 @@ namespace ts {
function hasPrimitiveConstraint(type: TypeParameter): boolean {
const constraint = getConstraintOfTypeParameter(type);
return !!constraint && maybeTypeOfKind(constraint, TypeFlags.Primitive | TypeFlags.Index);
return !!constraint && maybeTypeOfKind(constraint.flags & TypeFlags.Conditional ? getDefaultConstraintOfConditionalType(constraint as ConditionalType) : constraint, TypeFlags.Primitive | TypeFlags.Index);
}
function isObjectLiteralType(type: Type) {
@@ -14169,9 +14247,11 @@ namespace ts {
(type === falseType || type === regularFalseType) ? TypeFacts.FalseFacts : TypeFacts.TrueFacts;
}
if (flags & TypeFlags.Object) {
return isFunctionObjectType(<ObjectType>type) ?
strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts :
strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts;
return getObjectFlags(type) & ObjectFlags.Anonymous && isEmptyObjectType(<ObjectType>type) ?
strictNullChecks ? TypeFacts.EmptyObjectStrictFacts : TypeFacts.EmptyObjectFacts :
isFunctionObjectType(<ObjectType>type) ?
strictNullChecks ? TypeFacts.FunctionStrictFacts : TypeFacts.FunctionFacts :
strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts;
}
if (flags & (TypeFlags.Void | TypeFlags.Undefined)) {
return TypeFacts.UndefinedFacts;
@@ -14734,6 +14814,14 @@ namespace ts {
// reference 'x.y.z', we may be at an assignment to 'x.y' or 'x'. In that case,
// return the declared type.
if (containsMatchingReference(reference, node)) {
// A matching dotted name might also be an expando property on a function *expression*,
// in which case we continue control flow analysis back to the function's declaration
if (isVariableDeclaration(node) && (isInJSFile(node) || isVarConst(node))) {
const init = getDeclaredExpandoInitializer(node);
if (init && (init.kind === SyntaxKind.FunctionExpression || init.kind === SyntaxKind.ArrowFunction)) {
return getTypeAtFlowNode(flow.antecedent);
}
}
return declaredType;
}
// Assignment doesn't affect reference
@@ -15083,23 +15171,24 @@ namespace ts {
return getTypeWithFacts(assumeTrue ? mapType(type, narrowTypeForTypeof) : type, facts);
function narrowTypeForTypeof(type: Type) {
if (assumeTrue && !(type.flags & TypeFlags.Union)) {
if (type.flags & TypeFlags.Unknown && literal.text === "object") {
return getUnionType([nonPrimitiveType, nullType]);
if (type.flags & TypeFlags.Unknown && literal.text === "object") {
return getUnionType([nonPrimitiveType, nullType]);
}
// We narrow a non-union type to an exact primitive type if the non-union type
// is a supertype of that primitive type. For example, type 'any' can be narrowed
// to one of the primitive types.
const targetType = literal.text === "function" ? globalFunctionType : typeofTypesByName.get(literal.text);
if (targetType) {
if (isTypeSubtypeOf(type, targetType)) {
return type;
}
// We narrow a non-union type to an exact primitive type if the non-union type
// is a supertype of that primitive type. For example, type 'any' can be narrowed
// to one of the primitive types.
const targetType = literal.text === "function" ? globalFunctionType : typeofTypesByName.get(literal.text);
if (targetType) {
if (isTypeSubtypeOf(targetType, type)) {
return isTypeAny(type) ? targetType : getIntersectionType([type, targetType]); // Intersection to handle `string` being a subtype of `keyof T`
}
if (type.flags & TypeFlags.Instantiable) {
const constraint = getBaseConstraintOfType(type) || anyType;
if (isTypeSubtypeOf(targetType, constraint)) {
return getIntersectionType([type, targetType]);
}
if (isTypeSubtypeOf(targetType, type)) {
return targetType;
}
if (type.flags & TypeFlags.Instantiable) {
const constraint = getBaseConstraintOfType(type) || anyType;
if (isTypeSubtypeOf(targetType, constraint)) {
return getIntersectionType([type, targetType]);
}
}
}
@@ -16951,7 +17040,7 @@ namespace ts {
(node.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>node).operatorToken.kind === SyntaxKind.EqualsToken);
}
function checkArrayLiteral(node: ArrayLiteralExpression, checkMode: CheckMode | undefined): Type {
function checkArrayLiteral(node: ArrayLiteralExpression, checkMode: CheckMode | undefined, forceTuple: boolean | undefined): Type {
const elements = node.elements;
const elementCount = elements.length;
let hasNonEndingSpreadElement = false;
@@ -16973,7 +17062,7 @@ namespace ts {
// get the contextual element type from it. So we do something similar to
// getContextualTypeForElementExpression, which will crucially not error
// if there is no index type / iterated type.
const restArrayType = checkExpression((<SpreadElement>e).expression, checkMode);
const restArrayType = checkExpression((<SpreadElement>e).expression, checkMode, forceTuple);
const restElementType = getIndexTypeOfType(restArrayType, IndexKind.Number) ||
getIteratedTypeOrElementType(restArrayType, /*errorNode*/ undefined, /*allowStringInput*/ false, /*allowAsyncIterables*/ false, /*checkAssignability*/ false);
if (restElementType) {
@@ -16982,7 +17071,7 @@ namespace ts {
}
else {
const elementContextualType = getContextualTypeForElementExpression(contextualType, index);
const type = checkExpressionForMutableLocation(e, checkMode, elementContextualType);
const type = checkExpressionForMutableLocation(e, checkMode, elementContextualType, forceTuple);
elementTypes.push(type);
}
if (index < elementCount - 1 && e.kind === SyntaxKind.SpreadElement) {
@@ -17020,6 +17109,9 @@ namespace ts {
}
return createTupleType(elementTypes, minLength, hasRestElement);
}
else if (forceTuple) {
return createTupleType(elementTypes, minLength, hasRestElement);
}
}
return getArrayLiteralType(elementTypes, UnionReduction.Subtype);
}
@@ -18208,7 +18300,7 @@ namespace ts {
// Referencing abstract properties within their own constructors is not allowed
if ((flags & ModifierFlags.Abstract) && isThisProperty(node) && symbolHasNonMethodDeclaration(prop)) {
const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)!);
if (declaringClassDeclaration && isNodeUsedDuringClassInitialization(node, declaringClassDeclaration)) {
if (declaringClassDeclaration && isNodeUsedDuringClassInitialization(node)) {
error(errorNode, Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, symbolToString(prop), getTextOfIdentifierOrLiteral(declaringClassDeclaration.name!)); // TODO: GH#18217
return false;
}
@@ -18395,6 +18487,9 @@ namespace ts {
}
}
}
else if (strictNullChecks && prop && prop.valueDeclaration && isPropertyAccessExpression(prop.valueDeclaration) && getAssignmentDeclarationPropertyAccessKind(prop.valueDeclaration)) {
assumeUninitialized = true;
}
const flowType = getFlowTypeOfReference(node, propType, assumeUninitialized ? getOptionalType(propType) : propType);
if (assumeUninitialized && !(getFalsyFlags(propType) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) {
error(right, Diagnostics.Property_0_is_used_before_being_assigned, symbolToString(prop!)); // TODO: GH#18217
@@ -20192,18 +20287,15 @@ namespace ts {
assigned || inferred;
}
function getAssignedClassType(symbol: Symbol) {
function getAssignedClassType(symbol: Symbol): Type | undefined {
const decl = symbol.valueDeclaration;
const assignmentSymbol = decl && decl.parent &&
(isFunctionDeclaration(decl) && getSymbolOfNode(decl) ||
isBinaryExpression(decl.parent) && getSymbolOfNode(decl.parent.left) ||
isVariableDeclaration(decl.parent) && getSymbolOfNode(decl.parent));
if (assignmentSymbol) {
const prototype = forEach(assignmentSymbol.declarations, getAssignedJSPrototype);
if (prototype) {
return checkExpression(prototype);
}
}
const prototype = assignmentSymbol && assignmentSymbol.exports && assignmentSymbol.exports.get("prototype" as __String);
const init = prototype && getAssignedJSPrototype(prototype.valueDeclaration);
return init ? checkExpression(init) : undefined;
}
function getAssignedJSPrototype(node: Node) {
@@ -22067,11 +22159,11 @@ namespace ts {
return false;
}
function checkExpressionForMutableLocation(node: Expression, checkMode: CheckMode | undefined, contextualType?: Type): Type {
function checkExpressionForMutableLocation(node: Expression, checkMode: CheckMode | undefined, contextualType?: Type, forceTuple?: boolean): Type {
if (arguments.length === 2) {
contextualType = getContextualType(node);
}
const type = checkExpression(node, checkMode);
const type = checkExpression(node, checkMode, forceTuple);
return isTypeAssertion(node) ? type :
getWidenedLiteralLikeTypeForContextualType(type, contextualType);
}
@@ -22171,13 +22263,13 @@ namespace ts {
// object, it serves as an indicator that all contained function and arrow expressions should be considered to
// have the wildcard function type; this form of type check is used during overload resolution to exclude
// contextually typed function and arrow expressions in the initial phase.
function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode): Type {
function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode, forceTuple?: boolean): Type {
let type: Type;
if (node.kind === SyntaxKind.QualifiedName) {
type = checkQualifiedName(<QualifiedName>node);
}
else {
const uninstantiatedType = checkExpressionWorker(node, checkMode);
const uninstantiatedType = checkExpressionWorker(node, checkMode, forceTuple);
type = instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode);
}
@@ -22207,7 +22299,7 @@ namespace ts {
return checkExpression(node.expression, checkMode);
}
function checkExpressionWorker(node: Expression, checkMode: CheckMode | undefined): Type {
function checkExpressionWorker(node: Expression, checkMode: CheckMode | undefined, forceTuple?: boolean): Type {
switch (node.kind) {
case SyntaxKind.Identifier:
return checkIdentifier(<Identifier>node);
@@ -22232,7 +22324,7 @@ namespace ts {
case SyntaxKind.RegularExpressionLiteral:
return globalRegExpType;
case SyntaxKind.ArrayLiteralExpression:
return checkArrayLiteral(<ArrayLiteralExpression>node, checkMode);
return checkArrayLiteral(<ArrayLiteralExpression>node, checkMode, forceTuple);
case SyntaxKind.ObjectLiteralExpression:
return checkObjectLiteral(<ObjectLiteralExpression>node, checkMode);
case SyntaxKind.PropertyAccessExpression:
@@ -27419,12 +27511,12 @@ namespace ts {
return result;
}
function isNodeUsedDuringClassInitialization(node: Node, classDeclaration: ClassLikeDeclaration) {
function isNodeUsedDuringClassInitialization(node: Node) {
return !!findAncestor(node, element => {
if ((isConstructorDeclaration(element) && nodeIsPresent(element.body) || isPropertyDeclaration(element)) && element.parent === classDeclaration) {
if (isConstructorDeclaration(element) && nodeIsPresent(element.body) || isPropertyDeclaration(element)) {
return true;
}
else if (element === classDeclaration || isFunctionLikeDeclaration(element)) {
else if (isClassLike(element) || isFunctionLikeDeclaration(element)) {
return "quit";
}
+42 -5
View File
@@ -172,6 +172,8 @@ namespace ts {
es2018: ScriptTarget.ES2018,
esnext: ScriptTarget.ESNext,
}),
affectsSourceFile: true,
affectsModuleResolution: true,
paramType: Diagnostics.VERSION,
showInSimplifiedHelpView: true,
category: Diagnostics.Basic_Options,
@@ -190,6 +192,7 @@ namespace ts {
es2015: ModuleKind.ES2015,
esnext: ModuleKind.ESNext
}),
affectsModuleResolution: true,
paramType: Diagnostics.KIND,
showInSimplifiedHelpView: true,
category: Diagnostics.Basic_Options,
@@ -202,6 +205,7 @@ namespace ts {
name: "lib",
type: libMap
},
affectsModuleResolution: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Basic_Options,
description: Diagnostics.Specify_library_files_to_be_included_in_the_compilation
@@ -209,6 +213,7 @@ namespace ts {
{
name: "allowJs",
type: "boolean",
affectsModuleResolution: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Basic_Options,
description: Diagnostics.Allow_javascript_files_to_be_compiled
@@ -226,6 +231,7 @@ namespace ts {
"react-native": JsxEmit.ReactNative,
"react": JsxEmit.React
}),
affectsSourceFile: true,
paramType: Diagnostics.KIND,
showInSimplifiedHelpView: true,
category: Diagnostics.Basic_Options,
@@ -336,6 +342,7 @@ namespace ts {
{
name: "noImplicitAny",
type: "boolean",
affectsSemanticDiagnostics: true,
strictFlag: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Strict_Type_Checking_Options,
@@ -344,6 +351,7 @@ namespace ts {
{
name: "strictNullChecks",
type: "boolean",
affectsSemanticDiagnostics: true,
strictFlag: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Strict_Type_Checking_Options,
@@ -352,6 +360,7 @@ namespace ts {
{
name: "strictFunctionTypes",
type: "boolean",
affectsSemanticDiagnostics: true,
strictFlag: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Strict_Type_Checking_Options,
@@ -360,6 +369,7 @@ namespace ts {
{
name: "strictPropertyInitialization",
type: "boolean",
affectsSemanticDiagnostics: true,
strictFlag: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Strict_Type_Checking_Options,
@@ -368,6 +378,7 @@ namespace ts {
{
name: "noImplicitThis",
type: "boolean",
affectsSemanticDiagnostics: true,
strictFlag: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Strict_Type_Checking_Options,
@@ -376,6 +387,7 @@ namespace ts {
{
name: "alwaysStrict",
type: "boolean",
affectsSourceFile: true,
strictFlag: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Strict_Type_Checking_Options,
@@ -410,6 +422,7 @@ namespace ts {
{
name: "noFallthroughCasesInSwitch",
type: "boolean",
affectsBindDiagnostics: true,
affectsSemanticDiagnostics: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Additional_Checks,
@@ -423,6 +436,7 @@ namespace ts {
node: ModuleResolutionKind.NodeJs,
classic: ModuleResolutionKind.Classic,
}),
affectsModuleResolution: true,
paramType: Diagnostics.STRATEGY,
category: Diagnostics.Module_Resolution_Options,
description: Diagnostics.Specify_module_resolution_strategy_Colon_node_Node_js_or_classic_TypeScript_pre_1_6,
@@ -430,6 +444,7 @@ namespace ts {
{
name: "baseUrl",
type: "string",
affectsModuleResolution: true,
isFilePath: true,
category: Diagnostics.Module_Resolution_Options,
description: Diagnostics.Base_directory_to_resolve_non_absolute_module_names
@@ -439,6 +454,7 @@ namespace ts {
// use type = object to copy the value as-is
name: "paths",
type: "object",
affectsModuleResolution: true,
isTSConfigOnly: true,
category: Diagnostics.Module_Resolution_Options,
description: Diagnostics.A_series_of_entries_which_re_map_imports_to_lookup_locations_relative_to_the_baseUrl
@@ -454,6 +470,7 @@ namespace ts {
type: "string",
isFilePath: true
},
affectsModuleResolution: true,
category: Diagnostics.Module_Resolution_Options,
description: Diagnostics.List_of_root_folders_whose_combined_content_represents_the_structure_of_the_project_at_runtime
},
@@ -465,6 +482,7 @@ namespace ts {
type: "string",
isFilePath: true
},
affectsModuleResolution: true,
category: Diagnostics.Module_Resolution_Options,
description: Diagnostics.List_of_folders_to_include_type_definitions_from
},
@@ -475,6 +493,7 @@ namespace ts {
name: "types",
type: "string"
},
affectsModuleResolution: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Module_Resolution_Options,
description: Diagnostics.Type_declaration_files_to_be_included_in_compilation
@@ -633,12 +652,14 @@ namespace ts {
{
name: "noLib",
type: "boolean",
affectsModuleResolution: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Do_not_include_the_default_library_file_lib_d_ts
},
{
name: "noResolve",
type: "boolean",
affectsModuleResolution: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Do_not_add_triple_slash_references_or_imported_modules_to_the_list_of_compiled_files
},
@@ -651,6 +672,7 @@ namespace ts {
{
name: "disableSizeLimit",
type: "boolean",
affectsSourceFile: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Disable_size_limitations_on_JavaScript_projects
},
@@ -696,6 +718,7 @@ namespace ts {
{
name: "allowUnusedLabels",
type: "boolean",
affectsBindDiagnostics: true,
affectsSemanticDiagnostics: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Do_not_report_errors_on_unused_labels
@@ -703,6 +726,7 @@ namespace ts {
{
name: "allowUnreachableCode",
type: "boolean",
affectsBindDiagnostics: true,
affectsSemanticDiagnostics: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Do_not_report_errors_on_unreachable_code
@@ -730,6 +754,7 @@ namespace ts {
{
name: "maxNodeModuleJsDepth",
type: "number",
// TODO: GH#27108 affectsModuleResolution: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.The_maximum_dependency_depth_to_search_under_node_modules_and_load_JavaScript_files
},
@@ -759,6 +784,18 @@ namespace ts {
}
];
/* @internal */
export const semanticDiagnosticsOptionDeclarations: ReadonlyArray<CommandLineOption> =
optionDeclarations.filter(option => !!option.affectsSemanticDiagnostics);
/* @internal */
export const moduleResolutionOptionDeclarations: ReadonlyArray<CommandLineOption> =
optionDeclarations.filter(option => !!option.affectsModuleResolution);
/* @internal */
export const sourceFileAffectingCompilerOptions: ReadonlyArray<CommandLineOption> = optionDeclarations.filter(option =>
!!option.affectsSourceFile || !!option.affectsModuleResolution || !!option.affectsBindDiagnostics);
/* @internal */
export const buildOpts: CommandLineOption[] = [
...commonOptionsWithBuild,
@@ -1993,7 +2030,7 @@ namespace ts {
if (ownConfig.extendedConfigPath) {
// copy the resolution stack so it is never reused between branches in potential diamond-problem scenarios.
resolutionStack = resolutionStack.concat([resolvedPath]);
const extendedConfig = getExtendedConfig(sourceFile!, ownConfig.extendedConfigPath, host, basePath, resolutionStack, errors);
const extendedConfig = getExtendedConfig(sourceFile, ownConfig.extendedConfigPath, host, basePath, resolutionStack, errors);
if (extendedConfig && isSuccessfulParsedTsconfig(extendedConfig)) {
const baseRaw = extendedConfig.raw;
const raw = ownConfig.raw;
@@ -2134,7 +2171,7 @@ namespace ts {
}
function getExtendedConfig(
sourceFile: TsConfigSourceFile,
sourceFile: TsConfigSourceFile | undefined,
extendedConfigPath: string,
host: ParseConfigHost,
basePath: string,
@@ -2143,7 +2180,7 @@ namespace ts {
): ParsedTsconfig | undefined {
const extendedResult = readJsonConfigFile(extendedConfigPath, path => host.readFile(path));
if (sourceFile) {
(sourceFile.extendedSourceFiles || (sourceFile.extendedSourceFiles = [])).push(extendedResult.fileName);
sourceFile.extendedSourceFiles = [extendedResult.fileName];
}
if (extendedResult.parseDiagnostics.length) {
errors.push(...extendedResult.parseDiagnostics);
@@ -2153,8 +2190,8 @@ namespace ts {
const extendedDirname = getDirectoryPath(extendedConfigPath);
const extendedConfig = parseConfig(/*json*/ undefined, extendedResult, host, extendedDirname,
getBaseFileName(extendedConfigPath), resolutionStack, errors);
if (sourceFile) {
sourceFile.extendedSourceFiles!.push(...extendedResult.extendedSourceFiles!);
if (sourceFile && extendedResult.extendedSourceFiles) {
sourceFile.extendedSourceFiles!.push(...extendedResult.extendedSourceFiles);
}
if (isSuccessfulParsedTsconfig(extendedConfig)) {
+11 -3
View File
@@ -842,7 +842,7 @@ namespace ts {
return deduplicateSorted(sort(array, comparer), equalityComparer || comparer);
}
export function arrayIsEqualTo<T>(array1: ReadonlyArray<T> | undefined, array2: ReadonlyArray<T> | undefined, equalityComparer: (a: T, b: T) => boolean = equateValues): boolean {
export function arrayIsEqualTo<T>(array1: ReadonlyArray<T> | undefined, array2: ReadonlyArray<T> | undefined, equalityComparer: (a: T, b: T, index: number) => boolean = equateValues): boolean {
if (!array1 || !array2) {
return array1 === array2;
}
@@ -852,7 +852,7 @@ namespace ts {
}
for (let i = 0; i < array1.length; i++) {
if (!equalityComparer(array1[i], array2[i])) {
if (!equalityComparer(array1[i], array2[i], i)) {
return false;
}
}
@@ -1409,9 +1409,12 @@ namespace ts {
/**
* Tests whether a value is string
*/
export function isString(text: any): text is string {
export function isString(text: unknown): text is string {
return typeof text === "string";
}
export function isNumber(x: unknown): x is number {
return typeof x === "number";
}
export function tryCast<TOut extends TIn, TIn = any>(value: TIn | undefined, test: (value: TIn) => value is TOut): TOut | undefined;
export function tryCast<T>(value: T, test: (value: T) => boolean): T | undefined;
@@ -1534,6 +1537,7 @@ namespace ts {
* Every function should be assignable to this, but this should not be assignable to every function.
*/
export type AnyFunction = (...args: never[]) => void;
export type AnyConstructor = new (...args: unknown[]) => unknown;
export namespace Debug {
export let currentAssertionLevel = AssertionLevel.None;
@@ -2125,4 +2129,8 @@ namespace ts {
deleted(oldItems[oldIndex++]);
}
}
export function fill<T>(length: number, cb: (index: number) => T): T[] {
return new Array(length).fill(0).map((_, i) => cb(i));
}
}
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -1041,7 +1041,7 @@ namespace ts {
// SyntaxKind.TemplateMiddle
// SyntaxKind.TemplateTail
function emitLiteral(node: LiteralLikeNode) {
const text = getLiteralTextOfNode(node);
const text = getLiteralTextOfNode(node, printerOptions.neverAsciiEscape);
if ((printerOptions.sourceMap || printerOptions.inlineSourceMap)
&& (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) {
writeLiteral(text);
@@ -1532,7 +1532,7 @@ namespace ts {
expression = skipPartiallyEmittedExpressions(expression);
if (isNumericLiteral(expression)) {
// check if numeric literal is a decimal literal that was originally written with a dot
const text = getLiteralTextOfNode(<LiteralExpression>expression);
const text = getLiteralTextOfNode(<LiteralExpression>expression, /*neverAsciiEscape*/ true);
return !expression.numericLiteralFlags
&& !stringContains(text, tokenToString(SyntaxKind.DotToken)!);
}
@@ -3306,20 +3306,20 @@ namespace ts {
return getSourceTextOfNodeFromSourceFile(currentSourceFile, node, includeTrivia);
}
function getLiteralTextOfNode(node: LiteralLikeNode): string {
function getLiteralTextOfNode(node: LiteralLikeNode, neverAsciiEscape: boolean | undefined): string {
if (node.kind === SyntaxKind.StringLiteral && (<StringLiteral>node).textSourceNode) {
const textSourceNode = (<StringLiteral>node).textSourceNode!;
if (isIdentifier(textSourceNode)) {
return getEmitFlags(node) & EmitFlags.NoAsciiEscaping ?
return neverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ?
`"${escapeString(getTextOfNode(textSourceNode))}"` :
`"${escapeNonAsciiString(getTextOfNode(textSourceNode))}"`;
}
else {
return getLiteralTextOfNode(textSourceNode);
return getLiteralTextOfNode(textSourceNode, neverAsciiEscape);
}
}
return getLiteralText(node, currentSourceFile);
return getLiteralText(node, currentSourceFile, neverAsciiEscape);
}
/**
+1 -1
View File
@@ -235,7 +235,7 @@ namespace ts {
// Modifiers
export function createModifier<T extends Modifier["kind"]>(kind: T) {
export function createModifier<T extends Modifier["kind"]>(kind: T): Token<T> {
return createToken(kind);
}
+159
View File
@@ -0,0 +1,159 @@
/* @internal */
namespace ts {
export interface InspectValueOptions {
readonly fileNameToRequire: string;
}
export const enum ValueKind { Const, Array, FunctionOrClass, Object }
export interface ValueInfoBase {
readonly name: string;
}
export type ValueInfo = ValueInfoSimple | ValueInfoArray | ValueInfoFunctionOrClass | ValueInfoObject;
export interface ValueInfoSimple extends ValueInfoBase {
readonly kind: ValueKind.Const;
readonly typeName: string;
readonly comment?: string | undefined;
}
export interface ValueInfoFunctionOrClass extends ValueInfoBase {
readonly kind: ValueKind.FunctionOrClass;
readonly source: string | number; // For a native function, this is the length.
readonly prototypeMembers: ReadonlyArray<ValueInfo>;
readonly namespaceMembers: ReadonlyArray<ValueInfo>;
}
export interface ValueInfoArray extends ValueInfoBase {
readonly kind: ValueKind.Array;
readonly inner: ValueInfo;
}
export interface ValueInfoObject extends ValueInfoBase {
readonly kind: ValueKind.Object;
readonly members: ReadonlyArray<ValueInfo>;
}
export function inspectModule(fileNameToRequire: string): ValueInfo {
return inspectValue(removeFileExtension(getBaseFileName(fileNameToRequire)), tryRequire(fileNameToRequire));
}
export function inspectValue(name: string, value: unknown): ValueInfo {
return getValueInfo(name, value, getRecurser());
}
type Recurser = <T>(obj: unknown, name: string, cbOk: () => T, cbFail: (isCircularReference: boolean, keyStack: ReadonlyArray<string>) => T) => T;
function getRecurser(): Recurser {
const seen = new Set<unknown>();
const nameStack: string[] = [];
return (obj, name, cbOk, cbFail) => {
if (seen.has(obj) || nameStack.length > 4) {
return cbFail(seen.has(obj), nameStack);
}
seen.add(obj);
nameStack.push(name);
const res = cbOk();
nameStack.pop();
seen.delete(obj);
return res;
};
}
function getValueInfo(name: string, value: unknown, recurser: Recurser): ValueInfo {
return recurser(value, name,
(): ValueInfo => {
if (typeof value === "function") return getFunctionOrClassInfo(value as AnyFunction, name, recurser);
if (typeof value === "object") {
const builtin = getBuiltinType(name, value as object, recurser);
if (builtin !== undefined) return builtin;
const entries = getEntriesOfObject(value as object);
return { kind: ValueKind.Object, name, members: flatMap(entries, ({ key, value }) => getValueInfo(key, value, recurser)) };
}
return { kind: ValueKind.Const, name, typeName: isNullOrUndefined(value) ? "any" : typeof value };
},
(isCircularReference, keyStack) => anyValue(name, ` ${isCircularReference ? "Circular reference" : "Too-deep object hierarchy"} from ${keyStack.join(".")}`));
}
function getFunctionOrClassInfo(fn: AnyFunction, name: string, recurser: Recurser): ValueInfoFunctionOrClass {
const prototypeMembers = getPrototypeMembers(fn, recurser);
const namespaceMembers = flatMap(getEntriesOfObject(fn), ({ key, value }) => getValueInfo(key, value, recurser));
const toString = cast(Function.prototype.toString.call(fn), isString);
const source = stringContains(toString, "{ [native code] }") ? getFunctionLength(fn) : toString;
return { kind: ValueKind.FunctionOrClass, name, source, namespaceMembers, prototypeMembers };
}
const builtins: () => ReadonlyMap<AnyConstructor> = memoize(() => {
const map = createMap<AnyConstructor>();
for (const { key, value } of getEntriesOfObject(global)) {
if (typeof value === "function" && typeof value.prototype === "object" && value !== Object) {
map.set(key, value as AnyConstructor);
}
}
return map;
});
function getBuiltinType(name: string, value: object, recurser: Recurser): ValueInfo | undefined {
return isArray(value)
? { name, kind: ValueKind.Array, inner: value.length && getValueInfo("element", first(value), recurser) || anyValue(name) }
: forEachEntry(builtins(), (builtin, builtinName): ValueInfo | undefined =>
value instanceof builtin ? { kind: ValueKind.Const, name, typeName: builtinName } : undefined);
}
function getPrototypeMembers(fn: AnyFunction, recurser: Recurser): ReadonlyArray<ValueInfo> {
const prototype = fn.prototype as unknown;
// tslint:disable-next-line no-unnecessary-type-assertion (TODO: update LKG and it will really be unnecessary)
return typeof prototype !== "object" || prototype === null ? emptyArray : mapDefined(getEntriesOfObject(prototype as object), ({ key, value }) =>
key === "constructor" ? undefined : getValueInfo(key, value, recurser));
}
const ignoredProperties: ReadonlySet<string> = new Set(["arguments", "caller", "constructor", "eval", "super_"]);
const reservedFunctionProperties: ReadonlySet<string> = new Set(Object.getOwnPropertyNames(noop));
interface ObjectEntry { readonly key: string; readonly value: unknown; }
function getEntriesOfObject(obj: object): ReadonlyArray<ObjectEntry> {
const seen = createMap<true>();
const entries: ObjectEntry[] = [];
let chain = obj;
while (!isNullOrUndefined(chain) && chain !== Object.prototype && chain !== Function.prototype) {
for (const key of Object.getOwnPropertyNames(chain)) {
if (!isJsPrivate(key) &&
!ignoredProperties.has(key) &&
(typeof obj !== "function" || !reservedFunctionProperties.has(key)) &&
// Don't add property from a higher prototype if it already exists in a lower one
addToSeen(seen, key)) {
const value = safeGetPropertyOfObject(chain, key);
// Don't repeat "toString" that matches signature from Object.prototype
if (!(key === "toString" && typeof value === "function" && value.length === 0)) {
entries.push({ key, value });
}
}
}
chain = Object.getPrototypeOf(chain);
}
return entries.sort((e1, e2) => compareStringsCaseSensitive(e1.key, e2.key));
}
function getFunctionLength(fn: AnyFunction): number {
return tryCast(safeGetPropertyOfObject(fn, "length"), isNumber) || 0;
}
function safeGetPropertyOfObject(obj: object, key: string): unknown {
const desc = Object.getOwnPropertyDescriptor(obj, key);
return desc && desc.value;
}
function isNullOrUndefined(value: unknown): value is null | undefined {
return value == null; // tslint:disable-line
}
function anyValue(name: string, comment?: string): ValueInfo {
return { kind: ValueKind.Const, name, typeName: "any", comment };
}
export function isJsPrivate(name: string): boolean {
return name.startsWith("_");
}
function tryRequire(fileNameToRequire: string): unknown {
try {
return require(fileNameToRequire);
}
catch {
return undefined;
}
}
}
+11 -2
View File
@@ -779,14 +779,23 @@ namespace ts {
*/
/* @internal */
export function resolveJSModule(moduleName: string, initialDir: string, host: ModuleResolutionHost): string {
const { resolvedModule, failedLookupLocations } =
nodeModuleNameResolverWorker(moduleName, initialDir, { moduleResolution: ModuleResolutionKind.NodeJs, allowJs: true }, host, /*cache*/ undefined, /*jsOnly*/ true);
const { resolvedModule, failedLookupLocations } = tryResolveJSModuleWorker(moduleName, initialDir, host);
if (!resolvedModule) {
throw new Error(`Could not resolve JS module '${moduleName}' starting at '${initialDir}'. Looked in: ${failedLookupLocations.join(", ")}`);
}
return resolvedModule.resolvedFileName;
}
/* @internal */
export function tryResolveJSModule(moduleName: string, initialDir: string, host: ModuleResolutionHost): string | undefined {
const { resolvedModule } = tryResolveJSModuleWorker(moduleName, initialDir, host);
return resolvedModule && resolvedModule.resolvedFileName;
}
function tryResolveJSModuleWorker(moduleName: string, initialDir: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
return nodeModuleNameResolverWorker(moduleName, initialDir, { moduleResolution: ModuleResolutionKind.NodeJs, allowJs: true }, host, /*cache*/ undefined, /*jsOnly*/ true);
}
export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache): ResolvedModuleWithFailedLookupLocations {
return nodeModuleNameResolverWorker(moduleName, getDirectoryPath(containingFile), compilerOptions, host, cache, /*jsOnly*/ false);
}
+58 -34
View File
@@ -455,7 +455,7 @@ namespace ts {
}
// If project references dont match
if (!arrayIsEqualTo(program.getProjectReferences(), projectReferences)) {
if (!arrayIsEqualTo(program.getProjectReferences(), projectReferences, projectReferenceUptoDate)) {
return false;
}
@@ -483,9 +483,27 @@ namespace ts {
return true;
function sourceFileNotUptoDate(sourceFile: SourceFile): boolean {
return sourceFile.version !== getSourceVersion(sourceFile.path) ||
hasInvalidatedResolution(sourceFile.path);
function sourceFileNotUptoDate(sourceFile: SourceFile) {
return !sourceFileVersionUptoDate(sourceFile) ||
hasInvalidatedResolution(sourceFile.resolvedPath || sourceFile.path);
}
function sourceFileVersionUptoDate(sourceFile: SourceFile) {
return sourceFile.version === getSourceVersion(sourceFile.resolvedPath || sourceFile.path);
}
function projectReferenceUptoDate(oldRef: ProjectReference, newRef: ProjectReference, index: number) {
if (!projectReferenceIsEqualTo(oldRef, newRef)) {
return false;
}
const oldResolvedRef = program!.getResolvedProjectReferences()![index];
if (oldResolvedRef) {
// If sourceFile for the oldResolvedRef existed, check the version for uptodate
return sourceFileVersionUptoDate(oldResolvedRef.sourceFile);
}
// In old program, not able to resolve project reference path,
// so if config file doesnt exist, it is uptodate.
return !fileExists(resolveProjectReferencePath(oldRef));
}
}
@@ -496,23 +514,15 @@ namespace ts {
}
/**
* Determined if source file needs to be re-created even if its text hasn't changed
* Determine if source file needs to be re-created even if its text hasn't changed
*/
function shouldProgramCreateNewSourceFiles(program: Program | undefined, newOptions: CompilerOptions) {
// If any of these options change, we can't reuse old source file even if version match
// The change in options like these could result in change in syntax tree change
const oldOptions = program && program.getCompilerOptions();
return oldOptions && (
oldOptions.target !== newOptions.target ||
oldOptions.module !== newOptions.module ||
oldOptions.moduleResolution !== newOptions.moduleResolution ||
oldOptions.noResolve !== newOptions.noResolve ||
oldOptions.jsx !== newOptions.jsx ||
oldOptions.allowJs !== newOptions.allowJs ||
oldOptions.disableSizeLimit !== newOptions.disableSizeLimit ||
oldOptions.baseUrl !== newOptions.baseUrl ||
!equalOwnProperties(oldOptions.paths, newOptions.paths)
);
function shouldProgramCreateNewSourceFiles(program: Program | undefined, newOptions: CompilerOptions): boolean {
if (!program) return false;
// If any compiler options change, we can't reuse old source file even if version match
// The change in options like these could result in change in syntax tree or `sourceFile.bindDiagnostics`.
const oldOptions = program.getCompilerOptions();
return !!sourceFileAffectingCompilerOptions.some(option =>
!isJsonEqual(getCompilerOptionValue(oldOptions, option), getCompilerOptionValue(newOptions, option)));
}
function createCreateProgramOptions(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): CreateProgramOptions {
@@ -666,8 +676,9 @@ namespace ts {
const parsedRef = parseProjectReferenceConfigFile(ref);
resolvedProjectReferences!.push(parsedRef);
if (parsedRef) {
if (parsedRef.commandLine.options.outFile) {
const dtsOutfile = changeExtension(parsedRef.commandLine.options.outFile, ".d.ts");
const out = parsedRef.commandLine.options.outFile || parsedRef.commandLine.options.out;
if (out) {
const dtsOutfile = changeExtension(out, ".d.ts");
processSourceFile(dtsOutfile, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
}
addProjectReferenceRedirects(parsedRef.commandLine, projectReferenceRedirects);
@@ -766,7 +777,8 @@ namespace ts {
getConfigFileParsingDiagnostics,
getResolvedModuleWithFailedLookupLocationsFromCache,
getProjectReferences,
getResolvedProjectReferences
getResolvedProjectReferences,
getProjectReferenceRedirect
};
verifyCompilerOptions();
@@ -1233,6 +1245,13 @@ namespace ts {
}
resolvedTypeReferenceDirectives = oldProgram.getResolvedTypeReferenceDirectives();
resolvedProjectReferences = oldProgram.getResolvedProjectReferences();
if (resolvedProjectReferences) {
resolvedProjectReferences.forEach(ref => {
if (ref) {
addProjectReferenceRedirects(ref.commandLine, projectReferenceRedirects);
}
});
}
sourceFileToPackageName = oldProgram.sourceFileToPackageName;
redirectTargetsMap = oldProgram.redirectTargetsMap;
@@ -1288,12 +1307,13 @@ namespace ts {
const ref = projectReferences[i];
const resolvedRefOpts = resolvedProjectReferences![i]!.commandLine;
if (ref.prepend && resolvedRefOpts && resolvedRefOpts.options) {
const out = resolvedRefOpts.options.outFile || resolvedRefOpts.options.out;
// Upstream project didn't have outFile set -- skip (error will have been issued earlier)
if (!resolvedRefOpts.options.outFile) continue;
if (!out) continue;
const dtsFilename = changeExtension(resolvedRefOpts.options.outFile, ".d.ts");
const js = host.readFile(resolvedRefOpts.options.outFile) || `/* Input file ${resolvedRefOpts.options.outFile} was missing */\r\n`;
const jsMapPath = resolvedRefOpts.options.outFile + ".map"; // TODO: try to read sourceMappingUrl comment from the file
const dtsFilename = changeExtension(out, ".d.ts");
const js = host.readFile(out) || `/* Input file ${out} was missing */\r\n`;
const jsMapPath = out + ".map"; // TODO: try to read sourceMappingUrl comment from the file
const jsMap = host.readFile(jsMapPath);
const dts = host.readFile(dtsFilename) || `/* Input file ${dtsFilename} was missing */\r\n`;
const dtsMapPath = dtsFilename + ".map";
@@ -2435,9 +2455,10 @@ namespace ts {
createDiagnosticForReference(i, Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.path);
}
if (ref.prepend) {
if (resolvedRefOpts.outFile) {
if (!host.fileExists(resolvedRefOpts.outFile)) {
createDiagnosticForReference(i, Diagnostics.Output_file_0_from_project_1_does_not_exist, resolvedRefOpts.outFile, ref.path);
const out = resolvedRefOpts.outFile || resolvedRefOpts.out;
if (out) {
if (!host.fileExists(out)) {
createDiagnosticForReference(i, Diagnostics.Output_file_0_from_project_1_does_not_exist, out, ref.path);
}
}
else {
@@ -2511,7 +2532,7 @@ namespace ts {
}
if (options.declarationDir) {
if (!options.declaration) {
if (!getEmitDeclarations(options)) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "declarationDir", "declaration");
}
if (options.out || options.outFile) {
@@ -2588,8 +2609,8 @@ namespace ts {
}
}
if (!options.noEmit && options.allowJs && options.declaration) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration");
if (!options.noEmit && options.allowJs && getEmitDeclarations(options)) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", options.declaration ? "declaration" : "composite");
}
if (options.checkJs && !options.allowJs) {
@@ -2829,7 +2850,10 @@ namespace ts {
export function parseConfigHostFromCompilerHost(host: CompilerHost): ParseConfigFileHost {
return {
fileExists: f => host.fileExists(f),
readDirectory: (root, extensions, includes, depth?) => host.readDirectory ? host.readDirectory(root, extensions, includes, depth) : [],
readDirectory(root, extensions, excludes, includes, depth) {
Debug.assertDefined(host.readDirectory, "'CompilerHost.readDirectory' must be implemented to correctly process 'projectReferences'");
return host.readDirectory!(root, extensions, excludes, includes, depth);
},
readFile: f => host.readFile(f),
useCaseSensitiveFileNames: host.useCaseSensitiveFileNames(),
getCurrentDirectory: () => host.getCurrentDirectory(),
+7 -6
View File
@@ -285,16 +285,17 @@ namespace ts {
}
function getOutFileOutputs(project: ParsedCommandLine): ReadonlyArray<string> {
if (!project.options.outFile) {
const out = project.options.outFile || project.options.out;
if (!out) {
return Debug.fail("outFile must be set");
}
const outputs: string[] = [];
outputs.push(project.options.outFile);
outputs.push(out);
if (project.options.sourceMap) {
outputs.push(`${project.options.outFile}.map`);
outputs.push(`${out}.map`);
}
if (getEmitDeclarations(project.options)) {
const dts = changeExtension(project.options.outFile, Extension.Dts);
const dts = changeExtension(out, Extension.Dts);
outputs.push(dts);
if (project.options.declarationMap) {
outputs.push(`${dts}.map`);
@@ -862,7 +863,7 @@ namespace ts {
if (buildProject) {
buildSingleInvalidatedProject(buildProject.project, buildProject.reloadLevel);
if (hasPendingInvalidatedProjects()) {
if (!timerToBuildInvalidatedProject) {
if (options.watch && !timerToBuildInvalidatedProject) {
scheduleBuildInvalidatedProject();
}
}
@@ -1248,7 +1249,7 @@ namespace ts {
}
export function getAllProjectOutputs(project: ParsedCommandLine): ReadonlyArray<string> {
if (project.options.outFile) {
if (project.options.outFile || project.options.out) {
return getOutFileOutputs(project);
}
else {
+2 -1
View File
@@ -52,6 +52,7 @@
"resolutionCache.ts",
"moduleSpecifiers.ts",
"watch.ts",
"tsbuild.ts"
"tsbuild.ts",
"inspectValue.ts",
]
}
+12 -1
View File
@@ -2551,6 +2551,11 @@ namespace ts {
fileName: string;
/* @internal */ path: Path;
text: string;
/** Resolved path can be different from path property,
* when file is included through project reference is mapped to its output instead of source
* in that case resolvedPath = path to output file
* path = input file's path
*/
/* @internal */ resolvedPath: Path;
/**
@@ -2819,6 +2824,7 @@ namespace ts {
getProjectReferences(): ReadonlyArray<ProjectReference> | undefined;
getResolvedProjectReferences(): (ResolvedProjectReference | undefined)[] | undefined;
/*@internal*/ getProjectReferenceRedirect(fileName: string): string | undefined;
}
/* @internal */
@@ -3670,6 +3676,7 @@ namespace ts {
export interface NodeLinks {
flags: NodeCheckFlags; // Set of flags specific to Node
resolvedType?: Type; // Cached type of type node
resolvedEnumType?: Type; // Cached constraint type from enum jsdoc tag
resolvedSignature?: Signature; // Cached signature of signature node or call expression
resolvedSignatures?: Map<Signature[]>; // Cached signatures of jsx node
resolvedSymbol?: Symbol; // Cached name resolution result
@@ -4569,6 +4576,9 @@ namespace ts {
showInSimplifiedHelpView?: boolean;
category?: DiagnosticMessage;
strictFlag?: true; // true if the option is one of the flag under strict
affectsSourceFile?: true; // true if we should recreate SourceFiles after this option changes
affectsModuleResolution?: true; // currently same effect as `affectsSourceFile`
affectsBindDiagnostics?: true; // true if this affects binding (currently same effect as `affectsSourceFile`)
affectsSemanticDiagnostics?: true; // true if option affects semantic diagnostics
}
@@ -4964,7 +4974,7 @@ namespace ts {
/* @internal */
export interface EmitNode {
annotatedNodes?: Node[]; // Tracks Parse-tree nodes with EmitNodes for eventual cleanup.
flags: EmitFlags; // Flags that customize emit
flags: EmitFlags; // Flags that customize emit
leadingComments?: SynthesizedComment[]; // Synthesized leading comments
trailingComments?: SynthesizedComment[]; // Synthesized trailing comments
commentRange?: TextRange; // The text range to use when emitting leading or trailing comments
@@ -5324,6 +5334,7 @@ namespace ts {
/*@internal*/ inlineSourceMap?: boolean;
/*@internal*/ extendedDiagnostics?: boolean;
/*@internal*/ onlyPrintJsDocStyle?: boolean;
/*@internal*/ neverAsciiEscape?: boolean;
}
/* @internal */
+16 -27
View File
@@ -101,22 +101,8 @@ namespace ts {
}
export function changesAffectModuleResolution(oldOptions: CompilerOptions, newOptions: CompilerOptions): boolean {
return !oldOptions ||
(oldOptions.module !== newOptions.module) ||
(oldOptions.moduleResolution !== newOptions.moduleResolution) ||
(oldOptions.noResolve !== newOptions.noResolve) ||
(oldOptions.target !== newOptions.target) ||
(oldOptions.noLib !== newOptions.noLib) ||
(oldOptions.jsx !== newOptions.jsx) ||
(oldOptions.allowJs !== newOptions.allowJs) ||
(oldOptions.rootDir !== newOptions.rootDir) ||
(oldOptions.configFilePath !== newOptions.configFilePath) ||
(oldOptions.baseUrl !== newOptions.baseUrl) ||
(oldOptions.maxNodeModuleJsDepth !== newOptions.maxNodeModuleJsDepth) ||
!arrayIsEqualTo(oldOptions.lib, newOptions.lib) ||
!arrayIsEqualTo(oldOptions.typeRoots, newOptions.typeRoots) ||
!arrayIsEqualTo(oldOptions.rootDirs, newOptions.rootDirs) ||
!equalOwnProperties(oldOptions.paths, newOptions.paths);
return oldOptions.configFilePath !== newOptions.configFilePath || moduleResolutionOptionDeclarations.some(o =>
!isJsonEqual(getCompilerOptionValue(oldOptions, o), getCompilerOptionValue(newOptions, o)));
}
/**
@@ -538,14 +524,14 @@ namespace ts {
return emitNode && emitNode.flags || 0;
}
export function getLiteralText(node: LiteralLikeNode, sourceFile: SourceFile) {
export function getLiteralText(node: LiteralLikeNode, sourceFile: SourceFile, neverAsciiEscape: boolean | undefined) {
// If we don't need to downlevel and we can reach the original source text using
// the node's parent reference, then simply get the text as it was originally written.
if (!nodeIsSynthesized(node) && node.parent && !(isNumericLiteral(node) && node.numericLiteralFlags & TokenFlags.ContainsSeparator)) {
return getSourceTextOfNodeFromSourceFile(sourceFile, node);
}
const escapeText = getEmitFlags(node) & EmitFlags.NoAsciiEscaping ? escapeString : escapeNonAsciiString;
const escapeText = neverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ? escapeString : escapeNonAsciiString;
// If we can't reach the original source text, use the canonical form if it's a number,
// or a (possibly escaped) quoted form of the original text if it's string-like.
@@ -7091,9 +7077,8 @@ namespace ts {
const moduleKind = getEmitModuleKind(compilerOptions);
return compilerOptions.allowSyntheticDefaultImports !== undefined
? compilerOptions.allowSyntheticDefaultImports
: compilerOptions.esModuleInterop
? moduleKind !== ModuleKind.None && moduleKind < ModuleKind.ES2015
: moduleKind === ModuleKind.System;
: compilerOptions.esModuleInterop ||
moduleKind === ModuleKind.System;
}
export function getEmitDeclarations(compilerOptions: CompilerOptions): boolean {
@@ -7106,13 +7091,13 @@ namespace ts {
return compilerOptions[flag] === undefined ? !!compilerOptions.strict : !!compilerOptions[flag];
}
export function compilerOptionsAffectSemanticDiagnostics(newOptions: CompilerOptions, oldOptions: CompilerOptions) {
if (oldOptions === newOptions) {
return false;
}
export function compilerOptionsAffectSemanticDiagnostics(newOptions: CompilerOptions, oldOptions: CompilerOptions): boolean {
return oldOptions !== newOptions &&
semanticDiagnosticsOptionDeclarations.some(option => !isJsonEqual(getCompilerOptionValue(oldOptions, option), getCompilerOptionValue(newOptions, option)));
}
return optionDeclarations.some(option => (!!option.strictFlag && getStrictOptionValue(newOptions, option.name as StrictOptionName) !== getStrictOptionValue(oldOptions, option.name as StrictOptionName)) ||
(!!option.affectsSemanticDiagnostics && !newOptions[option.name] !== !oldOptions[option.name]));
export function getCompilerOptionValue(options: CompilerOptions, option: CommandLineOption): unknown {
return option.strictFlag ? getStrictOptionValue(options, option.name as StrictOptionName) : options[option.name];
}
export function hasZeroOrOneAsteriskCharacter(str: string): boolean {
@@ -8380,4 +8365,8 @@ namespace ts {
// '/// <reference no-default-lib="true"/>' directive.
return options.skipLibCheck && sourceFile.isDeclarationFile || options.skipDefaultLibCheck && sourceFile.hasNoDefaultLib;
}
export function isJsonEqual(a: unknown, b: unknown): boolean {
return a === b || typeof a === "object" && a !== null && typeof b === "object" && b !== null && equalOwnProperties(a as MapLike<unknown>, b as MapLike<unknown>, isJsonEqual);
}
}
+2 -1
View File
@@ -546,7 +546,8 @@ namespace ts {
},
maxNumberOfFilesToIterateForInvalidation: host.maxNumberOfFilesToIterateForInvalidation,
getCurrentProgram,
writeLog
writeLog,
readDirectory: (path, extensions, exclude, include, depth?) => directoryStructureHost.readDirectory!(path, extensions, exclude, include, depth),
};
// Cache for the module resolution
const resolutionCache = createResolutionCache(compilerHost, configFileName ?
+28 -5
View File
@@ -2502,9 +2502,7 @@ Actual: ${stringify(fullActual)}`);
const { changes, commands } = this.languageService.getCombinedCodeFix({ type: "file", fileName: this.activeFile.fileName }, fixId, this.formatCodeSettings, ts.emptyOptions);
assert.deepEqual<ReadonlyArray<{}> | undefined>(commands, expectedCommands);
assert(changes.every(c => c.fileName === this.activeFile.fileName), "TODO: support testing codefixes that touch multiple files");
this.applyChanges(changes);
this.verifyCurrentFileContent(newFileContent);
this.verifyNewContent({ newFileContent }, changes);
}
/**
@@ -3389,6 +3387,19 @@ Actual: ${stringify(fullActual)}`);
private getApplicableRefactorsWorker(positionOrRange: number | ts.TextRange, fileName: string, preferences = ts.emptyOptions): ReadonlyArray<ts.ApplicableRefactorInfo> {
return this.languageService.getApplicableRefactors(fileName, positionOrRange, preferences) || ts.emptyArray;
}
public generateTypes(examples: ReadonlyArray<FourSlashInterface.GenerateTypesOptions>): void {
for (const { name = "example", value, output, outputBaseline } of examples) {
const actual = ts.generateTypesForModule(name, value, this.formatCodeSettings);
if (outputBaseline) {
if (actual === undefined) throw ts.Debug.fail();
Harness.Baseline.runBaseline(ts.combinePaths("generateTypes", outputBaseline + ts.Extension.Dts), actual);
}
else {
assert.equal(actual, output, `generateTypes output for ${name} does not match`);
}
}
}
}
function updateTextRangeForTextChanges({ pos, end }: ts.TextRange, textChanges: ReadonlyArray<ts.TextChange>): ts.TextRange {
@@ -3442,7 +3453,7 @@ Actual: ${stringify(fullActual)}`);
// Parse out the files and their metadata
const testData = parseTestData(absoluteBasePath, content, absoluteFileName);
const state = new TestState(absoluteBasePath, testType, testData);
const output = ts.transpileModule(content, { reportDiagnostics: true });
const output = ts.transpileModule(content, { reportDiagnostics: true, compilerOptions: { target: ts.ScriptTarget.ES2015 } });
if (output.diagnostics!.length > 0) {
throw new Error(`Syntax error in ${absoluteBasePath}: ${output.diagnostics![0].messageText}`);
}
@@ -4512,6 +4523,18 @@ namespace FourSlashInterface {
public noMoveToNewFile(): void {
this.state.noMoveToNewFile();
}
public generateTypes(...options: GenerateTypesOptions[]): void {
this.state.generateTypes(options);
}
}
export interface GenerateTypesOptions {
readonly name?: string;
readonly value: unknown;
// Exactly one of these should be set:
readonly output?: string;
readonly outputBaseline?: string;
}
export class Edit {
@@ -4901,7 +4924,7 @@ namespace FourSlashInterface {
export interface VerifyCodeFixAllOptions {
fixId: string;
fixAllDescription: string;
newFileContent: string;
newFileContent: NewFileContent;
commands: ReadonlyArray<{}>;
}
+9 -3
View File
@@ -187,9 +187,10 @@ interface Array<T> {}`
}
export function checkArray(caption: string, actual: ReadonlyArray<string>, expected: ReadonlyArray<string>) {
checkMapKeys(caption, arrayToMap(actual, identity), expected);
assert.equal(actual.length, expected.length, `${caption}: incorrect actual number of files, expected:\r\n${expected.join("\r\n")}\r\ngot: ${actual.join("\r\n")}`);
for (const f of expected) {
assert.equal(true, contains(actual, f), `${caption}: expected to find ${f} in ${actual}`);
assert.isTrue(contains(actual, f), `${caption}: expected to find ${f} in ${actual}`);
}
}
@@ -654,7 +655,7 @@ interface Array<T> {}`
invokeWatcherCallbacks(this.watchedDirectoriesRecursive.get(this.toPath(folderFullPath))!, cb => this.directoryCallback(cb, relativePath));
}
invokeFileWatcher(fileFullPath: string, eventKind: FileWatcherEventKind, useFileNameInCallback?: boolean) {
private invokeFileWatcher(fileFullPath: string, eventKind: FileWatcherEventKind, useFileNameInCallback?: boolean) {
invokeWatcherCallbacks(this.watchedFiles.get(this.toPath(fileFullPath))!, ({ cb, fileName }) => cb(useFileNameInCallback ? fileName : fileFullPath, eventKind));
}
@@ -934,7 +935,12 @@ interface Array<T> {}`
const folder = this.fs.get(base) as FsFolder;
Debug.assert(isFsFolder(folder));
this.addFileOrFolderInFolder(folder, file);
if (!this.fs.has(file.path)) {
this.addFileOrFolderInFolder(folder, file);
}
else {
this.modifyFile(path, content);
}
}
write(message: string) {
+1
View File
@@ -4,6 +4,7 @@ namespace ts.server {
export const ActionSet: ActionSet = "action::set";
export const ActionInvalidate: ActionInvalidate = "action::invalidate";
export const ActionPackageInstalled: ActionPackageInstalled = "action::packageInstalled";
export const ActionValueInspected: ActionValueInspected = "action::valueInspected";
export const EventTypesRegistry: EventTypesRegistry = "event::typesRegistry";
export const EventBeginInstallTypes: EventBeginInstallTypes = "event::beginInstallTypes";
export const EventEndInstallTypes: EventEndInstallTypes = "event::endInstallTypes";
+16 -3
View File
@@ -2,6 +2,7 @@ declare namespace ts.server {
export type ActionSet = "action::set";
export type ActionInvalidate = "action::invalidate";
export type ActionPackageInstalled = "action::packageInstalled";
export type ActionValueInspected = "action::valueInspected";
export type EventTypesRegistry = "event::typesRegistry";
export type EventBeginInstallTypes = "event::beginInstallTypes";
export type EventEndInstallTypes = "event::endInstallTypes";
@@ -12,7 +13,7 @@ declare namespace ts.server {
}
export interface TypingInstallerResponse {
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | ActionValueInspected | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
}
export interface TypingInstallerRequestWithProjectName {
@@ -20,7 +21,7 @@ declare namespace ts.server {
}
/* @internal */
export type TypingInstallerRequestUnion = DiscoverTypings | CloseProject | TypesRegistryRequest | InstallPackageRequest;
export type TypingInstallerRequestUnion = DiscoverTypings | CloseProject | TypesRegistryRequest | InstallPackageRequest | InspectValueRequest;
export interface DiscoverTypings extends TypingInstallerRequestWithProjectName {
readonly fileNames: string[];
@@ -47,6 +48,12 @@ declare namespace ts.server {
readonly projectRootPath: Path;
}
/* @internal */
export interface InspectValueRequest {
readonly kind: "inspectValue";
readonly options: InspectValueOptions;
}
/* @internal */
export interface TypesRegistryResponse extends TypingInstallerResponse {
readonly kind: EventTypesRegistry;
@@ -59,6 +66,12 @@ declare namespace ts.server {
readonly message: string;
}
/* @internal */
export interface InspectValueResponse {
readonly kind: ActionValueInspected;
readonly result: ValueInfo;
}
export interface InitializationFailedResponse extends TypingInstallerResponse {
readonly kind: EventInitializationFailed;
readonly message: string;
@@ -106,5 +119,5 @@ declare namespace ts.server {
}
/* @internal */
export type TypingInstallerResponseUnion = SetTypings | InvalidateCachedTypings | TypesRegistryResponse | PackageInstalledResponse | InstallTypes | InitializationFailedResponse;
export type TypingInstallerResponseUnion = SetTypings | InvalidateCachedTypings | TypesRegistryResponse | PackageInstalledResponse | InspectValueResponse | InstallTypes | InitializationFailedResponse;
}
File diff suppressed because it is too large Load Diff
+9
View File
@@ -254,6 +254,11 @@ namespace ts.server {
installPackage(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult> {
return this.typingsCache.installPackage({ ...options, projectName: this.projectName, projectRootPath: this.toPath(this.currentDirectory) });
}
/* @internal */
inspectValue(options: InspectValueOptions): Promise<ValueInfo> {
return this.typingsCache.inspectValue(options);
}
private get typingsCache(): TypingsCache {
return this.projectService.typingsCache;
}
@@ -352,6 +357,10 @@ namespace ts.server {
return this.projectService.host.readFile(fileName);
}
writeFile(fileName: string, content: string): void {
return this.projectService.host.writeFile(fileName, content);
}
fileExists(file: string): boolean {
// As an optimization, don't hit the disks for files we already know don't exist
// (because we're watching for their creation).
+3
View File
@@ -1123,6 +1123,9 @@ namespace ts.server.protocol {
* Optional modifiers for the kind (such as 'public').
*/
kindModifiers: string;
/** Span of text to rename. */
triggerSpan: TextSpan;
}
/**
+25 -14
View File
@@ -336,16 +336,23 @@ namespace ts.server {
function combineProjectOutputForReferences(projects: Projects, defaultProject: Project, initialLocation: sourcemaps.SourceMappableLocation, projectService: ProjectService): ReadonlyArray<ReferencedSymbol> {
const outputs: ReferencedSymbol[] = [];
combineProjectOutputWorker<sourcemaps.SourceMappableLocation>(projects, defaultProject, initialLocation, projectService, ({ project, location }, tryAddToTodo) => {
combineProjectOutputWorker<sourcemaps.SourceMappableLocation>(projects, defaultProject, initialLocation, projectService, ({ project, location }, getMappedLocation) => {
for (const outputReferencedSymbol of project.getLanguageService().findReferences(location.fileName, location.position) || emptyArray) {
let symbolToAddTo = find(outputs, o => documentSpansEqual(o.definition, outputReferencedSymbol.definition));
const mappedDefinitionFile = getMappedLocation(project, documentSpanLocation(outputReferencedSymbol.definition));
const definition: ReferencedSymbolDefinitionInfo = mappedDefinitionFile === undefined ? outputReferencedSymbol.definition : {
...outputReferencedSymbol.definition,
textSpan: createTextSpan(mappedDefinitionFile.position, outputReferencedSymbol.definition.textSpan.length),
fileName: mappedDefinitionFile.fileName,
};
let symbolToAddTo = find(outputs, o => documentSpansEqual(o.definition, definition));
if (!symbolToAddTo) {
symbolToAddTo = { definition: outputReferencedSymbol.definition, references: [] };
symbolToAddTo = { definition, references: [] };
outputs.push(symbolToAddTo);
}
for (const ref of outputReferencedSymbol.references) {
if (!contains(symbolToAddTo.references, ref, documentSpansEqual) && !tryAddToTodo(project, documentSpanLocation(ref))) {
// If it's in a mapped file, that is added to the todo list by `getMappedLocation`.
if (!contains(symbolToAddTo.references, ref, documentSpansEqual) && !getMappedLocation(project, documentSpanLocation(ref))) {
symbolToAddTo.references.push(ref);
}
}
@@ -373,12 +380,17 @@ namespace ts.server {
}
}
type CombineProjectOutputCallback<TLocation extends sourcemaps.SourceMappableLocation | undefined> = (
where: ProjectAndLocation<TLocation>,
getMappedLocation: (project: Project, location: sourcemaps.SourceMappableLocation) => sourcemaps.SourceMappableLocation | undefined,
) => void;
function combineProjectOutputWorker<TLocation extends sourcemaps.SourceMappableLocation | undefined>(
projects: Projects,
defaultProject: Project,
initialLocation: TLocation,
projectService: ProjectService,
cb: (where: ProjectAndLocation<TLocation>, getMappedLocation: (project: Project, location: sourcemaps.SourceMappableLocation) => boolean) => void,
cb: CombineProjectOutputCallback<TLocation>,
getDefinition: (() => sourcemaps.SourceMappableLocation | undefined) | undefined,
): void {
let toDo: ProjectAndLocation<TLocation>[] | undefined;
@@ -417,13 +429,13 @@ namespace ts.server {
projectService: ProjectService,
toDo: ProjectAndLocation<TLocation>[] | undefined,
seenProjects: Map<true>,
cb: (where: ProjectAndLocation<TLocation>, getMappedLocation: (project: Project, location: sourcemaps.SourceMappableLocation) => boolean) => void,
cb: CombineProjectOutputCallback<TLocation>,
): ProjectAndLocation<TLocation>[] | undefined {
if (projectAndLocation.project.getCancellationToken().isCancellationRequested()) return undefined; // Skip rest of toDo if cancelled
cb(projectAndLocation, (project, location) => {
seenProjects.set(projectAndLocation.project.projectName, true);
const originalLocation = projectService.getOriginalLocationEnsuringConfiguredProject(project, location);
if (!originalLocation) return false;
if (!originalLocation) return undefined;
const originalScriptInfo = projectService.getScriptInfo(originalLocation.fileName)!;
toDo = toDo || [];
@@ -437,7 +449,7 @@ namespace ts.server {
for (const symlinkedProject of symlinkedProjects) addToTodo({ project: symlinkedProject, location: originalLocation as TLocation }, toDo!, seenProjects);
});
}
return true;
return originalLocation;
});
return toDo;
}
@@ -1149,13 +1161,12 @@ namespace ts.server {
if (!simplifiedResult) return locations;
const defaultProject = this.getDefaultProject(args);
const renameInfo = Session.mapRenameInfo(defaultProject.getLanguageService().getRenameInfo(file, position));
const renameInfo: protocol.RenameInfo = this.mapRenameInfo(defaultProject.getLanguageService().getRenameInfo(file, position), Debug.assertDefined(this.projectService.getScriptInfo(file)));
return { info: renameInfo, locs: this.toSpanGroups(locations) };
}
// strips 'triggerSpan'
private static mapRenameInfo({ canRename, localizedErrorMessage, displayName, fullDisplayName, kind, kindModifiers }: RenameInfo): protocol.RenameInfo {
return { canRename, localizedErrorMessage, displayName, fullDisplayName, kind, kindModifiers };
private mapRenameInfo({ canRename, localizedErrorMessage, displayName, fullDisplayName, kind, kindModifiers, triggerSpan }: RenameInfo, scriptInfo: ScriptInfo): protocol.RenameInfo {
return { canRename, localizedErrorMessage, displayName, fullDisplayName, kind, kindModifiers, triggerSpan: this.toLocationTextSpan(triggerSpan, scriptInfo) };
}
private toSpanGroups(locations: ReadonlyArray<RenameLocation>): ReadonlyArray<protocol.SpanGroup> {
@@ -1818,8 +1829,8 @@ namespace ts.server {
private applyCodeActionCommand(args: protocol.ApplyCodeActionCommandRequestArgs): {} {
const commands = args.command as CodeActionCommand | CodeActionCommand[]; // They should be sending back the command we sent them.
for (const command of toArray(commands)) {
const { project } = this.getFileAndProject(command);
project.getLanguageService().applyCodeActionCommand(command).then(
const { file, project } = this.getFileAndProject(command);
project.getLanguageService().applyCodeActionCommand(command, this.getFormatOptions(file)).then(
_result => { /* TODO: GH#20447 report success message? */ },
_error => { /* TODO: GH#20447 report errors */ });
}
+7
View File
@@ -8,6 +8,8 @@ namespace ts.server {
export interface ITypingsInstaller {
isKnownTypesPackageName(name: string): boolean;
installPackage(options: InstallPackageOptionsWithProject): Promise<ApplyCodeActionCommandResult>;
/* @internal */
inspectValue(options: InspectValueOptions): Promise<ValueInfo>;
enqueueInstallTypingsRequest(p: Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray<string> | undefined): void;
attach(projectService: ProjectService): void;
onProjectClosed(p: Project): void;
@@ -18,6 +20,7 @@ namespace ts.server {
isKnownTypesPackageName: returnFalse,
// Should never be called because we never provide a types registry.
installPackage: notImplemented,
inspectValue: notImplemented,
enqueueInstallTypingsRequest: noop,
attach: noop,
onProjectClosed: noop,
@@ -95,6 +98,10 @@ namespace ts.server {
return this.installer.installPackage(options);
}
inspectValue(options: InspectValueOptions): Promise<ValueInfo> {
return this.installer.inspectValue(options);
}
enqueueInstallTypingsForProject(project: Project, unresolvedImports: SortedReadonlyArray<string> | undefined, forceRefresh: boolean) {
const typeAcquisition = project.getTypeAcquisition();
@@ -14,17 +14,10 @@ namespace ts.codefix {
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, err) => convertToAsyncFunction(changes, err.file, err.start, context.program.getTypeChecker(), context)),
});
/*
custom type to encapsulate information for variable declarations synthesized in the refactor
numberOfUsesOriginal - number of times the variable should be assigned in the refactor
numberOfUsesSynthesized - count of how many times the variable has been assigned so far
At the end of the refactor, numberOfUsesOriginal should === numberOfUsesSynthesized
*/
interface SynthIdentifier {
identifier: Identifier;
types: Type[];
numberOfAssignmentsOriginal: number;
numberOfAssignmentsOriginal: number; // number of times the variable should be assigned in the refactor
}
interface SymbolAndIdentifier {
@@ -179,9 +172,9 @@ namespace ts.codefix {
// if the identifier refers to a function we want to add the new synthesized variable for the declaration (ex. blob in let blob = res(arg))
// Note - the choice of the last call signature is arbitrary
if (lastCallSignature && lastCallSignature.parameters.length && !synthNamesMap.has(symbolIdString)) {
const firstParameter = lastCallSignature.parameters[0];
const ident = isParameter(firstParameter.valueDeclaration) && tryCast(firstParameter.valueDeclaration.name, isIdentifier) || createOptimisticUniqueName("result");
if (lastCallSignature && !isFunctionLikeDeclaration(node.parent) && !synthNamesMap.has(symbolIdString)) {
const firstParameter = firstOrUndefined(lastCallSignature.parameters);
const ident = firstParameter && isParameter(firstParameter.valueDeclaration) && tryCast(firstParameter.valueDeclaration.name, isIdentifier) || createOptimisticUniqueName("result");
const synthName = getNewNameIfConflict(ident, collidingSymbolMap);
synthNamesMap.set(symbolIdString, synthName);
allVarNames.push({ identifier: synthName.identifier, symbol });
@@ -234,9 +227,7 @@ namespace ts.codefix {
if (renameInfo) {
const type = checker.getTypeAtLocation(node);
if (type) {
originalType.set(getNodeId(clone).toString(), type);
}
originalType.set(getNodeId(clone).toString(), type);
}
}
@@ -320,7 +311,7 @@ namespace ts.codefix {
const tryBlock = createBlock(transformExpression(node.expression, transformer, node, prevArgName));
const transformationBody = getTransformationBody(func, prevArgName, argName, node, transformer);
const catchArg = argName.identifier.text.length > 0 ? argName.identifier.text : "e";
const catchArg = argName ? argName.identifier.text : "e";
const catchClause = createCatchClause(catchArg, createBlock(transformationBody));
/*
@@ -362,7 +353,7 @@ namespace ts.codefix {
const transformationBody2 = getTransformationBody(rej, prevArgName, argNameRej, node, transformer);
const catchArg = argNameRej.identifier.text.length > 0 ? argNameRej.identifier.text : "e";
const catchArg = argNameRej ? argNameRej.identifier.text : "e";
const catchClause = createCatchClause(catchArg, createBlock(transformationBody2));
return [createTry(tryBlock, catchClause, /* finallyBlock */ undefined) as Statement];
@@ -379,21 +370,25 @@ namespace ts.codefix {
function transformPromiseCall(node: Expression, transformer: Transformer, prevArgName?: SynthIdentifier): Statement[] {
const shouldReturn = transformer.setOfExpressionsToReturn.get(getNodeId(node).toString());
// the identifier is empty when the handler (.then()) ignores the argument - In this situation we do not need to save the result of the promise returning call
const hasPrevArgName = prevArgName && prevArgName.identifier.text.length > 0;
const originalNodeParent = node.original ? node.original.parent : node.parent;
if (hasPrevArgName && !shouldReturn && (!originalNodeParent || isPropertyAccessExpression(originalNodeParent))) {
return createVariableDeclarationOrAssignment(prevArgName!, createAwait(node), transformer).concat(); // hack to make the types match
if (prevArgName && !shouldReturn && (!originalNodeParent || isPropertyAccessExpression(originalNodeParent))) {
return createTransformedStatement(prevArgName, createAwait(node), transformer);
}
else if (!hasPrevArgName && !shouldReturn && (!originalNodeParent || isPropertyAccessExpression(originalNodeParent))) {
else if (!prevArgName && !shouldReturn && (!originalNodeParent || isPropertyAccessExpression(originalNodeParent))) {
return [createStatement(createAwait(node))];
}
return [createReturn(getSynthesizedDeepClone(node))];
}
function createVariableDeclarationOrAssignment(prevArgName: SynthIdentifier, rightHandSide: Expression, transformer: Transformer): NodeArray<Statement> {
function createTransformedStatement(prevArgName: SynthIdentifier | undefined, rightHandSide: Expression, transformer: Transformer): MutableNodeArray<Statement> {
if (!prevArgName || prevArgName.identifier.text.length === 0) {
// if there's no argName to assign to, there still might be side effects
return createNodeArray([createStatement(rightHandSide)]);
}
if (prevArgName.types.length < prevArgName.numberOfAssignmentsOriginal) {
// if the variable has already been declared, we don't need "let" or "const"
return createNodeArray([createStatement(createAssignment(getSynthesizedDeepClone(prevArgName.identifier), rightHandSide))]);
}
@@ -402,42 +397,47 @@ namespace ts.codefix {
}
// should be kept up to date with isFixablePromiseArgument in suggestionDiagnostics.ts
function getTransformationBody(func: Node, prevArgName: SynthIdentifier | undefined, argName: SynthIdentifier, parent: CallExpression, transformer: Transformer): NodeArray<Statement> {
function getTransformationBody(func: Expression, prevArgName: SynthIdentifier | undefined, argName: SynthIdentifier | undefined, parent: CallExpression, transformer: Transformer): NodeArray<Statement> {
const hasPrevArgName = prevArgName && prevArgName.identifier.text.length > 0;
const hasArgName = argName && argName.identifier.text.length > 0;
const shouldReturn = transformer.setOfExpressionsToReturn.get(getNodeId(parent).toString());
switch (func.kind) {
case SyntaxKind.NullKeyword:
// do not produce a transformed statement for a null argument
break;
case SyntaxKind.Identifier:
// identifier includes undefined
if (!hasArgName) break;
case SyntaxKind.Identifier: // identifier includes undefined
if (!argName) {
// undefined was argument passed to promise handler
break;
}
const synthCall = createCall(getSynthesizedDeepClone(func) as Identifier, /*typeArguments*/ undefined, [argName.identifier]);
const synthCall = createCall(getSynthesizedDeepClone(func) as Identifier, /*typeArguments*/ undefined, argName ? [argName.identifier] : []);
if (shouldReturn) {
return createNodeArray([createReturn(synthCall)]);
}
if (!hasPrevArgName) break;
const type = transformer.originalTypeMap.get(getNodeId(func).toString());
const callSignatures = type && transformer.checker.getSignaturesOfType(type, SignatureKind.Call);
const returnType = callSignatures && callSignatures[0].getReturnType();
const varDeclOrAssignment = createVariableDeclarationOrAssignment(prevArgName!, createAwait(synthCall), transformer);
prevArgName!.types.push(returnType!);
const type = transformer.originalTypeMap.get(getNodeId(func).toString()) || transformer.checker.getTypeAtLocation(func);
const callSignatures = transformer.checker.getSignaturesOfType(type, SignatureKind.Call);
if (!callSignatures.length) {
// if identifier in handler has no call signatures, it's invalid
codeActionSucceeded = false;
break;
}
const returnType = callSignatures[0].getReturnType();
const varDeclOrAssignment = createTransformedStatement(prevArgName, createAwait(synthCall), transformer);
if (prevArgName) {
prevArgName.types.push(returnType);
}
return varDeclOrAssignment;
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
case SyntaxKind.ArrowFunction: {
const funcBody = (func as FunctionExpression | ArrowFunction).body;
// Arrow functions with block bodies { } will enter this control flow
if (isFunctionLikeDeclaration(func) && func.body && isBlock(func.body) && func.body.statements) {
if (isBlock(funcBody)) {
let refactoredStmts: Statement[] = [];
let seenReturnStatement = false;
for (const statement of func.body.statements) {
for (const statement of funcBody.statements) {
if (isReturnStatement(statement)) {
seenReturnStatement = true;
}
@@ -451,30 +451,34 @@ namespace ts.codefix {
}
return shouldReturn ? getSynthesizedDeepClones(createNodeArray(refactoredStmts)) :
removeReturns(createNodeArray(refactoredStmts), prevArgName!.identifier, transformer.constIdentifiers, seenReturnStatement);
removeReturns(createNodeArray(refactoredStmts), prevArgName!.identifier, transformer, seenReturnStatement);
}
else {
const funcBody = (<ArrowFunction>func).body;
const innerRetStmts = getReturnStatementsWithPromiseHandlers(createReturn(funcBody as Expression));
const innerRetStmts = getReturnStatementsWithPromiseHandlers(createReturn(funcBody));
const innerCbBody = getInnerTransformationBody(transformer, innerRetStmts, prevArgName);
if (innerCbBody.length > 0) {
return createNodeArray(innerCbBody);
}
if (hasPrevArgName && !shouldReturn) {
if (!shouldReturn) {
const type = transformer.checker.getTypeAtLocation(func);
const returnType = getLastCallSignature(type, transformer.checker)!.getReturnType();
const varDeclOrAssignment = createVariableDeclarationOrAssignment(prevArgName!, getSynthesizedDeepClone(funcBody) as Expression, transformer);
prevArgName!.types.push(returnType);
return varDeclOrAssignment;
const rightHandSide = getSynthesizedDeepClone(funcBody);
const possiblyAwaitedRightHandSide = !!transformer.checker.getPromisedTypeOfPromise(returnType) ? createAwait(rightHandSide) : rightHandSide;
const transformedStatement = createTransformedStatement(prevArgName, possiblyAwaitedRightHandSide, transformer);
if (prevArgName) {
prevArgName.types.push(returnType);
}
return transformedStatement;
}
else {
return createNodeArray([createReturn(getSynthesizedDeepClone(funcBody) as Expression)]);
return createNodeArray([createReturn(getSynthesizedDeepClone(funcBody))]);
}
}
}
default:
// We've found a transformation body we don't know how to handle, so the refactoring should no-op to avoid deleting code.
// If no cases apply, we've found a transformation body we don't know how to handle, so the refactoring should no-op to avoid deleting code.
codeActionSucceeded = false;
break;
}
@@ -487,13 +491,14 @@ namespace ts.codefix {
}
function removeReturns(stmts: NodeArray<Statement>, prevArgName: Identifier, constIdentifiers: Identifier[], seenReturnStatement: boolean): NodeArray<Statement> {
function removeReturns(stmts: NodeArray<Statement>, prevArgName: Identifier, transformer: Transformer, seenReturnStatement: boolean): NodeArray<Statement> {
const ret: Statement[] = [];
for (const stmt of stmts) {
if (isReturnStatement(stmt)) {
if (stmt.expression) {
const possiblyAwaitedExpression = isPromiseReturningExpression(stmt.expression, transformer.checker) ? createAwait(stmt.expression) : stmt.expression;
ret.push(createVariableStatement(/*modifiers*/ undefined,
(createVariableDeclarationList([createVariableDeclaration(prevArgName, /*type*/ undefined, stmt.expression)], getFlagOfIdentifier(prevArgName, constIdentifiers)))));
(createVariableDeclarationList([createVariableDeclaration(prevArgName, /*type*/ undefined, possiblyAwaitedExpression)], getFlagOfIdentifier(prevArgName, transformer.constIdentifiers)))));
}
}
else {
@@ -504,7 +509,7 @@ namespace ts.codefix {
// if block has no return statement, need to define prevArgName as undefined to prevent undeclared variables
if (!seenReturnStatement) {
ret.push(createVariableStatement(/*modifiers*/ undefined,
(createVariableDeclarationList([createVariableDeclaration(prevArgName, /*type*/ undefined, createIdentifier("undefined"))], getFlagOfIdentifier(prevArgName, constIdentifiers)))));
(createVariableDeclarationList([createVariableDeclaration(prevArgName, /*type*/ undefined, createIdentifier("undefined"))], getFlagOfIdentifier(prevArgName, transformer.constIdentifiers)))));
}
return createNodeArray(ret);
@@ -531,7 +536,7 @@ namespace ts.codefix {
return innerCbBody;
}
function getArgName(funcNode: Node, transformer: Transformer): SynthIdentifier {
function getArgName(funcNode: Expression, transformer: Transformer): SynthIdentifier | undefined {
const numberOfAssignmentsOriginal = 0;
const types: Type[] = [];
@@ -541,20 +546,21 @@ namespace ts.codefix {
if (isFunctionLikeDeclaration(funcNode)) {
if (funcNode.parameters.length > 0) {
const param = funcNode.parameters[0].name as Identifier;
name = getMapEntryIfExists(param);
name = getMapEntryOrDefault(param);
}
}
else if (isIdentifier(funcNode)) {
name = getMapEntryIfExists(funcNode);
name = getMapEntryOrDefault(funcNode);
}
if (!name || name.identifier === undefined || name.identifier.text === "_" || name.identifier.text === "undefined") {
return { identifier: createIdentifier(""), types, numberOfAssignmentsOriginal };
// return undefined argName when arg is null or undefined
if (!name || name.identifier.text === "undefined") {
return undefined;
}
return name;
function getMapEntryIfExists(identifier: Identifier): SynthIdentifier {
function getMapEntryOrDefault(identifier: Identifier): SynthIdentifier {
const originalNode = getOriginalNode(identifier);
const symbol = getSymbol(originalNode);
+131 -13
View File
@@ -1,6 +1,9 @@
/* @internal */
namespace ts.codefix {
const fixId = "fixCannotFindModule";
const fixName = "fixCannotFindModule";
const fixIdInstallTypesPackage = "installTypesPackage";
const fixIdGenerateTypes = "generateTypes";
const errorCodeCannotFindModule = Diagnostics.Cannot_find_module_0.code;
const errorCodes = [
errorCodeCannotFindModule,
@@ -10,26 +13,141 @@ namespace ts.codefix {
errorCodes,
getCodeActions: context => {
const { host, sourceFile, span: { start } } = context;
const packageName = getTypesPackageNameToInstall(host, sourceFile, start, context.errorCode);
return packageName === undefined ? []
: [createCodeFixAction(fixId, /*changes*/ [], [Diagnostics.Install_0, packageName], fixId, Diagnostics.Install_all_missing_types_packages, getCommand(sourceFile.fileName, packageName))];
const packageName = tryGetImportedPackageName(sourceFile, start);
if (packageName === undefined) return undefined;
const typesPackageName = getTypesPackageNameToInstall(packageName, host, context.errorCode);
return typesPackageName === undefined
? singleElementArray(tryGetGenerateTypesAction(context, packageName))
: [createCodeFixAction(fixName, /*changes*/ [], [Diagnostics.Install_0, typesPackageName], fixIdInstallTypesPackage, Diagnostics.Install_all_missing_types_packages, getInstallCommand(sourceFile.fileName, typesPackageName))];
},
fixIds: [fixIdInstallTypesPackage, fixIdGenerateTypes],
getAllCodeActions: context => {
let savedTypesDir: string | null | undefined = null; // tslint:disable-line no-null-keyword
return codeFixAll(context, errorCodes, (changes, diag, commands) => {
const packageName = tryGetImportedPackageName(diag.file, diag.start);
if (packageName === undefined) return undefined;
switch (context.fixId) {
case fixIdInstallTypesPackage: {
const pkg = getTypesPackageNameToInstall(packageName, context.host, diag.code);
if (pkg) {
commands.push(getInstallCommand(diag.file.fileName, pkg));
}
break;
}
case fixIdGenerateTypes: {
const typesDir = savedTypesDir !== null ? savedTypesDir : savedTypesDir = getOrCreateTypesDirectory(changes, context);
const command = typesDir === undefined ? undefined : tryGenerateTypes(typesDir, packageName, context);
if (command) commands.push(command);
break;
}
default:
Debug.fail(`Bad fixId: ${context.fixId}`);
}
});
},
fixIds: [fixId],
getAllCodeActions: context => codeFixAll(context, errorCodes, (_, diag, commands) => {
const pkg = getTypesPackageNameToInstall(context.host, diag.file, diag.start, diag.code);
if (pkg) {
commands.push(getCommand(diag.file.fileName, pkg));
}
}),
});
function getCommand(fileName: string, packageName: string): InstallPackageAction {
function tryGetGenerateTypesAction(context: CodeFixContextBase, packageName: string): CodeFixAction | undefined {
let command: GenerateTypesAction | undefined;
const changes = textChanges.ChangeTracker.with(context, t => {
const typesDir = getOrCreateTypesDirectory(t, context);
command = typesDir === undefined ? undefined : tryGenerateTypes(typesDir, packageName, context);
});
return command && createCodeFixAction(fixName, changes, [Diagnostics.Generate_types_for_0, packageName], fixIdGenerateTypes, Diagnostics.Generate_types_for_all_packages_without_types, command);
}
function tryGenerateTypes(typesDir: string, packageName: string, context: CodeFixContextBase): GenerateTypesAction | undefined {
const file = context.sourceFile.fileName;
const fileToGenerateTypesFor = tryResolveJSModule(packageName, getDirectoryPath(file), context.host as ModuleResolutionHost); // TODO: GH#18217
if (fileToGenerateTypesFor === undefined) return undefined;
const outputFileName = resolvePath(getDirectoryPath(context.program.getCompilerOptions().configFile!.fileName), typesDir, packageName + ".d.ts");
if (context.host.fileExists!(outputFileName)) return undefined;
return { type: "generate types", file, fileToGenerateTypesFor, outputFileName };
}
// If no types directory exists yet, adds it to tsconfig.json
function getOrCreateTypesDirectory(changes: textChanges.ChangeTracker, context: CodeFixContextBase): string | undefined {
const { configFile } = context.program.getCompilerOptions();
if (!configFile) return undefined;
const tsconfigObjectLiteral = getTsConfigObjectLiteralExpression(configFile);
if (!tsconfigObjectLiteral) return undefined;
const compilerOptionsProperty = findProperty(tsconfigObjectLiteral, "compilerOptions");
if (!compilerOptionsProperty) {
const newCompilerOptions = createObjectLiteral([makeDefaultBaseUrl(), makeDefaultPaths()]);
changes.insertNodeAtObjectStart(configFile, tsconfigObjectLiteral, createJsonPropertyAssignment("compilerOptions", newCompilerOptions));
return defaultTypesDirectoryName;
}
const compilerOptions = compilerOptionsProperty.initializer;
if (!isObjectLiteralExpression(compilerOptions)) return defaultTypesDirectoryName;
const baseUrl = getOrAddBaseUrl(changes, configFile, compilerOptions);
const typesDirectoryFromPathMapping = getOrAddPathMapping(changes, configFile, compilerOptions);
return combinePaths(baseUrl, typesDirectoryFromPathMapping);
}
const defaultBaseUrl = ".";
function makeDefaultBaseUrl(): PropertyAssignment {
return createJsonPropertyAssignment("baseUrl", createStringLiteral(defaultBaseUrl));
}
function getOrAddBaseUrl(changes: textChanges.ChangeTracker, tsconfig: TsConfigSourceFile, compilerOptions: ObjectLiteralExpression): string {
const baseUrlProp = findProperty(compilerOptions, "baseUrl");
if (baseUrlProp) {
return isStringLiteral(baseUrlProp.initializer) ? baseUrlProp.initializer.text : defaultBaseUrl;
}
else {
changes.insertNodeAtObjectStart(tsconfig, compilerOptions, makeDefaultBaseUrl());
return defaultBaseUrl;
}
}
const defaultTypesDirectoryName = "types";
function makeDefaultPathMapping(): PropertyAssignment {
return createJsonPropertyAssignment("*", createArrayLiteral([createStringLiteral(`${defaultTypesDirectoryName}/*`)]));
}
function makeDefaultPaths(): PropertyAssignment {
return createJsonPropertyAssignment("paths", createObjectLiteral([makeDefaultPathMapping()]));
}
function getOrAddPathMapping(changes: textChanges.ChangeTracker, tsconfig: TsConfigSourceFile, compilerOptions: ObjectLiteralExpression) {
const paths = findProperty(compilerOptions, "paths");
if (!paths || !isObjectLiteralExpression(paths.initializer)) {
changes.insertNodeAtObjectStart(tsconfig, compilerOptions, makeDefaultPaths());
return defaultTypesDirectoryName;
}
// Look for an existing path mapping. Should look like `"*": "foo/*"`.
const existing = firstDefined(paths.initializer.properties, prop =>
isPropertyAssignment(prop) && isStringLiteral(prop.name) && prop.name.text === "*" && isArrayLiteralExpression(prop.initializer)
? firstDefined(prop.initializer.elements, value => isStringLiteral(value) ? tryRemoveSuffix(value.text, "/*") : undefined)
: undefined);
if (existing) return existing;
changes.insertNodeAtObjectStart(tsconfig, paths.initializer, makeDefaultPathMapping());
return defaultTypesDirectoryName;
}
function createJsonPropertyAssignment(name: string, initializer: Expression) {
return createPropertyAssignment(createStringLiteral(name), initializer);
}
function findProperty(obj: ObjectLiteralExpression, name: string): PropertyAssignment | undefined {
return find(obj.properties, (p): p is PropertyAssignment => isPropertyAssignment(p) && !!p.name && isStringLiteral(p.name) && p.name.text === name);
}
function getInstallCommand(fileName: string, packageName: string): InstallPackageAction {
return { type: "install package", file: fileName, packageName };
}
function getTypesPackageNameToInstall(host: LanguageServiceHost, sourceFile: SourceFile, pos: number, diagCode: number): string | undefined {
function tryGetImportedPackageName(sourceFile: SourceFile, pos: number): string | undefined {
const moduleName = cast(getTokenAtPosition(sourceFile, pos), isStringLiteral).text;
const { packageName } = parsePackageName(moduleName);
return isExternalModuleNameRelative(packageName) ? undefined : packageName;
}
function getTypesPackageNameToInstall(packageName: string, host: LanguageServiceHost, diagCode: number): string | undefined {
return diagCode === errorCodeCannotFindModule
? (JsTyping.nodeCoreModules.has(packageName) ? "@types/node" : undefined)
: (host.isKnownTypesPackageName!(packageName) ? getTypesPackageName(packageName) : undefined); // TODO: GH#18217
+227
View File
@@ -0,0 +1,227 @@
/* @internal */
namespace ts {
export function generateTypesForModule(name: string, moduleValue: unknown, formatSettings: FormatCodeSettings): string {
return valueInfoToDeclarationFileText(inspectValue(name, moduleValue), formatSettings);
}
export function valueInfoToDeclarationFileText(valueInfo: ValueInfo, formatSettings: FormatCodeSettings): string {
return textChanges.getNewFileText(toStatements(valueInfo, OutputKind.ExportEquals), ScriptKind.TS, "\n", formatting.getFormatContext(formatSettings));
}
const enum OutputKind { ExportEquals, NamedExport, NamespaceMember }
function toNamespaceMemberStatements(info: ValueInfo): ReadonlyArray<Statement> {
return toStatements(info, OutputKind.NamespaceMember);
}
function toStatements(info: ValueInfo, kind: OutputKind): ReadonlyArray<Statement> {
const isDefault = info.name === InternalSymbolName.Default;
const name = isDefault ? "_default" : info.name;
if (!isValidIdentifier(name) || isDefault && kind !== OutputKind.NamedExport) return emptyArray;
const modifiers = isDefault && info.kind === ValueKind.FunctionOrClass ? [createModifier(SyntaxKind.ExportKeyword), createModifier(SyntaxKind.DefaultKeyword)]
: kind === OutputKind.ExportEquals ? [createModifier(SyntaxKind.DeclareKeyword)]
: kind === OutputKind.NamedExport ? [createModifier(SyntaxKind.ExportKeyword)]
: undefined;
const exportEquals = () => kind === OutputKind.ExportEquals ? [exportEqualsOrDefault(info.name, /*isExportEquals*/ true)] : emptyArray;
const exportDefault = () => isDefault ? [exportEqualsOrDefault("_default", /*isExportEquals*/ false)] : emptyArray;
switch (info.kind) {
case ValueKind.FunctionOrClass:
return [...exportEquals(), ...functionOrClassToStatements(modifiers, name, info)];
case ValueKind.Object:
const { members } = info;
if (kind === OutputKind.ExportEquals) {
return flatMap(members, v => toStatements(v, OutputKind.NamedExport));
}
if (members.some(m => m.kind === ValueKind.FunctionOrClass)) {
// If some member is a function, use a namespace so it gets a FunctionDeclaration or ClassDeclaration.
return [...exportDefault(), createNamespace(modifiers, name, flatMap(members, toNamespaceMemberStatements))];
}
// falls through
case ValueKind.Const:
case ValueKind.Array: {
const comment = info.kind === ValueKind.Const ? info.comment : undefined;
const constVar = createVariableStatement(modifiers, createVariableDeclarationList([createVariableDeclaration(name, toType(info))], NodeFlags.Const));
return [...exportEquals(), ...exportDefault(), addComment(constVar, comment)];
}
default:
return Debug.assertNever(info);
}
}
function exportEqualsOrDefault(name: string, isExportEquals: boolean): ExportAssignment {
return createExportAssignment(/*decorators*/ undefined, /*modifiers*/ undefined, isExportEquals, createIdentifier(name));
}
function functionOrClassToStatements(modifiers: Modifiers, name: string, { source, prototypeMembers, namespaceMembers }: ValueInfoFunctionOrClass): ReadonlyArray<Statement> {
const fnAst = parseClassOrFunctionBody(source);
const { parameters, returnType } = fnAst === undefined ? { parameters: emptyArray, returnType: anyType() } : getParametersAndReturnType(fnAst);
const instanceProperties = typeof fnAst === "object" ? getConstructorFunctionInstanceProperties(fnAst) : emptyArray;
const classStaticMembers: ClassElement[] | undefined =
instanceProperties.length !== 0 || prototypeMembers.length !== 0 || fnAst === undefined || typeof fnAst !== "number" && fnAst.kind === SyntaxKind.Constructor ? [] : undefined;
const namespaceStatements = flatMap(namespaceMembers, info => {
if (!isValidIdentifier(info.name)) return undefined;
if (classStaticMembers) {
switch (info.kind) {
case ValueKind.Object:
if (info.members.some(m => m.kind === ValueKind.FunctionOrClass)) {
break;
}
// falls through
case ValueKind.Array:
case ValueKind.Const:
classStaticMembers.push(
addComment(
createProperty(/*decorators*/ undefined, [createModifier(SyntaxKind.StaticKeyword)], info.name, /*questionOrExclamationToken*/ undefined, toType(info), /*initializer*/ undefined),
info.kind === ValueKind.Const ? info.comment : undefined));
return undefined;
case ValueKind.FunctionOrClass:
if (!info.namespaceMembers.length) { // Else, can't merge a static method with a namespace. Must make it a function on the namespace.
const sig = tryGetMethod(info, [createModifier(SyntaxKind.StaticKeyword)]);
if (sig) {
classStaticMembers.push(sig);
return undefined;
}
}
}
}
return toStatements(info, OutputKind.NamespaceMember);
});
const decl = classStaticMembers
? createClassDeclaration(
/*decorators*/ undefined,
modifiers,
name,
/*typeParameters*/ undefined,
/*heritageClauses*/ undefined,
[
...classStaticMembers,
...(parameters.length ? [createConstructor(/*decorators*/ undefined, /*modifiers*/ undefined, parameters, /*body*/ undefined)] : emptyArray),
...instanceProperties,
// ignore non-functions on the prototype
...mapDefined(prototypeMembers, info => info.kind === ValueKind.FunctionOrClass ? tryGetMethod(info) : undefined),
])
: createFunctionDeclaration(/*decorators*/ undefined, modifiers, /*asteriskToken*/ undefined, name, /*typeParameters*/ undefined, parameters, returnType, /*body*/ undefined);
return [decl, ...(namespaceStatements.length === 0 ? emptyArray : [createNamespace(modifiers && modifiers.map(m => getSynthesizedDeepClone(m)), name, namespaceStatements)])];
}
function tryGetMethod({ name, source }: ValueInfoFunctionOrClass, modifiers?: Modifiers): MethodDeclaration | undefined {
if (!isValidIdentifier(name)) return undefined;
const fnAst = parseClassOrFunctionBody(source);
if (fnAst === undefined || (typeof fnAst !== "number" && fnAst.kind === SyntaxKind.Constructor)) return undefined;
const sig = getParametersAndReturnType(fnAst);
return sig && createMethod(
/*decorators*/ undefined,
modifiers,
/*asteriskToken*/ undefined,
name,
/*questionToken*/ undefined,
/*typeParameters*/ undefined,
sig.parameters,
sig.returnType,
/*body*/ undefined);
}
function toType(info: ValueInfo): TypeNode {
switch (info.kind) {
case ValueKind.Const:
return createTypeReferenceNode(info.typeName, /*typeArguments*/ undefined);
case ValueKind.Array:
return createArrayTypeNode(toType(info.inner));
case ValueKind.FunctionOrClass:
return createTypeReferenceNode("Function", /*typeArguments*/ undefined); // Normally we create a FunctionDeclaration, but this can happen for a function in an array.
case ValueKind.Object:
return createTypeLiteralNode(info.members.map(m => createPropertySignature(/*modifiers*/ undefined, m.name, /*questionToken*/ undefined, toType(m), /*initializer*/ undefined)));
default:
return Debug.assertNever(info);
}
}
// Parses assignments to "this.x" in the constructor into class property declarations
function getConstructorFunctionInstanceProperties(fnAst: FunctionOrConstructorNode): ReadonlyArray<PropertyDeclaration> {
const members: PropertyDeclaration[] = [];
forEachOwnNodeOfFunction(fnAst, node => {
if (isAssignmentExpression(node, /*excludeCompoundAssignment*/ true) &&
isPropertyAccessExpression(node.left) && node.left.expression.kind === SyntaxKind.ThisKeyword) {
const name = node.left.name.text;
if (!isJsPrivate(name)) members.push(createProperty(/*decorators*/ undefined, /*modifiers*/ undefined, name, /*questionOrExclamationToken*/ undefined, anyType(), /*initializer*/ undefined));
}
});
return members;
}
interface ParametersAndReturnType { readonly parameters: ReadonlyArray<ParameterDeclaration>; readonly returnType: TypeNode; }
function getParametersAndReturnType(fnAst: FunctionOrConstructor): ParametersAndReturnType {
if (typeof fnAst === "number") {
return { parameters: fill(fnAst, i => makeParameter(`p${i}`, anyType())), returnType: anyType() };
}
let usedArguments = false, hasReturn = false;
forEachOwnNodeOfFunction(fnAst, node => {
usedArguments = usedArguments || isIdentifier(node) && node.text === "arguments";
hasReturn = hasReturn || isReturnStatement(node) && !!node.expression && node.expression.kind !== SyntaxKind.VoidExpression;
});
const parameters = [
...fnAst.parameters.map(p => makeParameter(`${p.name.getText()}`, inferParameterType(fnAst, p))),
...(usedArguments ? [makeRestParameter()] : emptyArray),
];
return { parameters, returnType: hasReturn ? anyType() : createKeywordTypeNode(SyntaxKind.VoidKeyword) };
}
function makeParameter(name: string, type: TypeNode): ParameterDeclaration {
return createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, name, /*questionToken*/ undefined, type);
}
function makeRestParameter(): ParameterDeclaration {
return createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, createToken(SyntaxKind.DotDotDotToken), "args", /*questionToken*/ undefined, createArrayTypeNode(anyType()));
}
type FunctionOrConstructorNode = FunctionExpression | ArrowFunction | ConstructorDeclaration | MethodDeclaration;
type FunctionOrConstructor = FunctionOrConstructorNode | number; // number is for native function
/** Returns 'undefined' for class with no declared constructor */
function parseClassOrFunctionBody(source: string | number): FunctionOrConstructor | undefined {
if (typeof source === "number") return source;
const classOrFunction = tryCast(parseExpression(source), (node): node is FunctionExpression | ArrowFunction | ClassExpression => isFunctionExpression(node) || isArrowFunction(node) || isClassExpression(node));
return classOrFunction
? isClassExpression(classOrFunction) ? find(classOrFunction.members, isConstructorDeclaration) : classOrFunction
// If that didn't parse, it's a method `m() {}`. Parse again inside of an object literal.
: cast(first(cast(parseExpression(`{ ${source} }`), isObjectLiteralExpression).properties), isMethodDeclaration);
}
function parseExpression(expr: string): Expression {
const text = `const _ = ${expr}`;
const srcFile = createSourceFile("test.ts", text, ScriptTarget.Latest, /*setParentNodes*/ true);
return first(cast(first(srcFile.statements), isVariableStatement).declarationList.declarations).initializer!;
}
function inferParameterType(_fn: FunctionOrConstructor, _param: ParameterDeclaration): TypeNode {
// TODO: Inspect function body for clues (see inferFromUsage.ts)
return anyType();
}
// Descends through all nodes in a function, but not in nested functions.
function forEachOwnNodeOfFunction(fnAst: FunctionOrConstructorNode, cb: (node: Node) => void) {
fnAst.body!.forEachChild(function recur(node) {
cb(node);
if (!isFunctionLike(node)) node.forEachChild(recur);
});
}
function isValidIdentifier(name: string): boolean {
const keyword = stringToToken(name);
return !(keyword && isNonContextualKeyword(keyword)) && isIdentifierText(name, ScriptTarget.ESNext);
}
type Modifiers = ReadonlyArray<Modifier> | undefined;
function addComment<T extends Node>(node: T, comment: string | undefined): T {
if (comment !== undefined) addSyntheticLeadingComment(node, SyntaxKind.SingleLineCommentTrivia, comment);
return node;
}
function anyType(): KeywordTypeNode {
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
}
function createNamespace(modifiers: Modifiers, name: string, statements: ReadonlyArray<Statement>): NamespaceDeclaration {
return createModuleDeclaration(/*decorators*/ undefined, modifiers, createIdentifier(name), createModuleBlock(statements), NodeFlags.Namespace) as NamespaceDeclaration;
}
}
+4 -4
View File
@@ -121,10 +121,6 @@ namespace ts {
const buckets = createMap<Map<DocumentRegistryEntry>>();
const getCanonicalFileName = createGetCanonicalFileName(!!useCaseSensitiveFileNames);
function getKeyForCompilationSettings(settings: CompilerOptions): DocumentRegistryBucketKey {
return <DocumentRegistryBucketKey>`_${settings.target}|${settings.module}|${settings.noResolve}|${settings.jsx}|${settings.allowJs}|${settings.baseUrl}|${JSON.stringify(settings.typeRoots)}|${JSON.stringify(settings.rootDirs)}|${JSON.stringify(settings.paths)}`;
}
function getBucketForCompilationSettings(key: DocumentRegistryBucketKey, createIfMissing: boolean): Map<DocumentRegistryEntry> {
let bucket = buckets.get(key);
if (!bucket && createIfMissing) {
@@ -273,4 +269,8 @@ namespace ts {
getKeyForCompilationSettings
};
}
function getKeyForCompilationSettings(settings: CompilerOptions): DocumentRegistryBucketKey {
return sourceFileAffectingCompilerOptions.map(option => getCompilerOptionValue(settings, option)).join("|") as DocumentRegistryBucketKey;
}
}
+1 -1
View File
@@ -385,7 +385,7 @@ namespace ts.FindAllReferences {
}
/** Iterates over all statements at the top level or in module declarations. Returns the first truthy result. */
function forEachPossibleImportOrExportStatement<T>(sourceFileLike: SourceFileLike, action: (statement: Statement) => T): T | undefined {
function forEachPossibleImportOrExportStatement<T>(sourceFileLike: SourceFileLike, action: (statement: Statement) => T) {
return forEach(sourceFileLike.kind === SyntaxKind.SourceFile ? sourceFileLike.statements : sourceFileLike.body!.statements, statement => // TODO: GH#18217
action(statement) || (isAmbientModuleDeclaration(statement) && forEach(statement.body && statement.body.statements, action)));
}
+8 -1
View File
@@ -39,11 +39,18 @@ namespace ts.Rename {
}
function getRenameInfoForModule(node: StringLiteralLike, sourceFile: SourceFile, moduleSymbol: Symbol): RenameInfo | undefined {
if (!isExternalModuleNameRelative(node.text)) {
return getRenameInfoError(Diagnostics.You_cannot_rename_a_module_via_a_global_import);
}
const moduleSourceFile = find(moduleSymbol.declarations, isSourceFile);
if (!moduleSourceFile) return undefined;
const withoutIndex = node.text.endsWith("/index") || node.text.endsWith("/index.js") ? undefined : tryRemoveSuffix(removeFileExtension(moduleSourceFile.fileName), "/index");
const name = withoutIndex === undefined ? moduleSourceFile.fileName : withoutIndex;
const kind = withoutIndex === undefined ? ScriptElementKind.moduleElement : ScriptElementKind.directory;
const indexAfterLastSlash = node.text.lastIndexOf("/") + 1;
// Span should only be the last component of the path. + 1 to account for the quote character.
const triggerSpan = createTextSpan(node.getStart(sourceFile) + 1 + indexAfterLastSlash, node.text.length - indexAfterLastSlash);
return {
canRename: true,
fileToRename: name,
@@ -52,7 +59,7 @@ namespace ts.Rename {
localizedErrorMessage: undefined,
fullDisplayName: name,
kindModifiers: ScriptElementKindModifier.none,
triggerSpan: createTriggerSpanForNode(node, sourceFile),
triggerSpan,
};
}
+25 -10
View File
@@ -1218,6 +1218,10 @@ namespace ts {
getDirectories: path => {
return host.getDirectories ? host.getDirectories(path) : [];
},
readDirectory(path, extensions, exclude, include, depth) {
Debug.assertDefined(host.readDirectory, "'LanguageServiceHost.readDirectory' must be implemented to correctly process 'projectReferences'");
return host.readDirectory!(path, extensions, exclude, include, depth);
},
onReleaseOldSourceFile,
hasInvalidatedResolution,
hasChangedAutomaticTypeDirectiveNames: host.hasChangedAutomaticTypeDirectiveNames
@@ -1804,25 +1808,36 @@ namespace ts {
return ts.getEditsForFileRename(getProgram()!, oldFilePath, newFilePath, host, formatting.getFormatContext(formatOptions), preferences, sourceMapper);
}
function applyCodeActionCommand(action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
function applyCodeActionCommand(action: CodeActionCommand[]): Promise<ApplyCodeActionCommandResult[]>;
function applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[]): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
function applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult>;
function applyCodeActionCommand(action: CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult[]>;
function applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
function applyCodeActionCommand(fileName: Path, action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
function applyCodeActionCommand(fileName: Path, action: CodeActionCommand[]): Promise<ApplyCodeActionCommandResult[]>;
function applyCodeActionCommand(fileName: Path | CodeActionCommand | CodeActionCommand[], actionOrUndefined?: CodeActionCommand | CodeActionCommand[]): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]> {
const action = typeof fileName === "string" ? actionOrUndefined! : fileName as CodeActionCommand[];
return isArray(action) ? Promise.all(action.map(applySingleCodeActionCommand)) : applySingleCodeActionCommand(action);
function applyCodeActionCommand(fileName: Path | CodeActionCommand | CodeActionCommand[], actionOrFormatSettingsOrUndefined?: CodeActionCommand | CodeActionCommand[] | FormatCodeSettings): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]> {
const action = typeof fileName === "string" ? actionOrFormatSettingsOrUndefined as CodeActionCommand | CodeActionCommand[] : fileName as CodeActionCommand[];
const formatSettings = typeof fileName !== "string" ? actionOrFormatSettingsOrUndefined as FormatCodeSettings : undefined;
return isArray(action) ? Promise.all(action.map(a => applySingleCodeActionCommand(a, formatSettings))) : applySingleCodeActionCommand(action, formatSettings);
}
function applySingleCodeActionCommand(action: CodeActionCommand): Promise<ApplyCodeActionCommandResult> {
function applySingleCodeActionCommand(action: CodeActionCommand, formatSettings: FormatCodeSettings | undefined): Promise<ApplyCodeActionCommandResult> {
const getPath = (path: string): Path => toPath(path, currentDirectory, getCanonicalFileName);
switch (action.type) {
case "install package":
return host.installPackage
? host.installPackage({ fileName: toPath(action.file, currentDirectory, getCanonicalFileName), packageName: action.packageName })
? host.installPackage({ fileName: getPath(action.file), packageName: action.packageName })
: Promise.reject("Host does not implement `installPackage`");
case "generate types": {
const { fileToGenerateTypesFor, outputFileName } = action;
if (!host.inspectValue) return Promise.reject("Host does not implement `installPackage`");
const valueInfoPromise = host.inspectValue({ fileNameToRequire: fileToGenerateTypesFor });
return valueInfoPromise.then(valueInfo => {
const fullOut = getPath(outputFileName);
host.writeFile!(fullOut, valueInfoToDeclarationFileText(valueInfo, formatSettings || testFormatSettings)); // TODO: GH#18217
return { successMessage: `Wrote types to '${fullOut}'` };
});
}
default:
return Debug.fail();
// TODO: Debug.assertNever(action); will only work if there is more than one type.
return Debug.assertNever(action);
}
}
+38 -20
View File
@@ -211,8 +211,8 @@ namespace ts.textChanges {
export class ChangeTracker {
private readonly changes: Change[] = [];
private readonly newFiles: { readonly oldFile: SourceFile, readonly fileName: string, readonly statements: ReadonlyArray<Statement> }[] = [];
private readonly classesWithNodesInsertedAtStart = createMap<ClassDeclaration>(); // Set<ClassDeclaration> implemented as Map<node id, ClassDeclaration>
private readonly newFiles: { readonly oldFile: SourceFile | undefined, readonly fileName: string, readonly statements: ReadonlyArray<Statement> }[] = [];
private readonly classesWithNodesInsertedAtStart = createMap<{ readonly node: ClassDeclaration | InterfaceDeclaration | ObjectLiteralExpression, readonly sourceFile: SourceFile }>(); // Set<ClassDeclaration> implemented as Map<node id, ClassDeclaration>
private readonly deletedNodes: { readonly sourceFile: SourceFile, readonly node: Node | NodeArray<TypeParameterDeclaration> }[] = [];
public static fromContext(context: TextChangesContext): ChangeTracker {
@@ -410,25 +410,33 @@ namespace ts.textChanges {
}
public insertNodeAtClassStart(sourceFile: SourceFile, cls: ClassLikeDeclaration | InterfaceDeclaration, newElement: ClassElement): void {
this.insertNodeAtStartWorker(sourceFile, cls, newElement);
}
public insertNodeAtObjectStart(sourceFile: SourceFile, obj: ObjectLiteralExpression, newElement: ObjectLiteralElementLike): void {
this.insertNodeAtStartWorker(sourceFile, obj, newElement);
}
private insertNodeAtStartWorker(sourceFile: SourceFile, cls: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression, newElement: ClassElement | ObjectLiteralElementLike): void {
const clsStart = cls.getStart(sourceFile);
const indentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn(getLineStartPositionForPosition(clsStart, sourceFile), clsStart, sourceFile, this.formatContext.options)
+ this.formatContext.options.indentSize!;
this.insertNodeAt(sourceFile, cls.members.pos, newElement, { indentation, ...this.getInsertNodeAtClassStartPrefixSuffix(sourceFile, cls) });
this.insertNodeAt(sourceFile, getMembersOrProperties(cls).pos, newElement, { indentation, ...this.getInsertNodeAtStartPrefixSuffix(sourceFile, cls) });
}
private getInsertNodeAtClassStartPrefixSuffix(sourceFile: SourceFile, cls: ClassLikeDeclaration | InterfaceDeclaration): { prefix: string, suffix: string } {
if (cls.members.length === 0) {
if (addToSeen(this.classesWithNodesInsertedAtStart, getNodeId(cls), cls)) {
private getInsertNodeAtStartPrefixSuffix(sourceFile: SourceFile, cls: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression): { prefix: string, suffix: string } {
const comma = isObjectLiteralExpression(cls) ? "," : "";
if (getMembersOrProperties(cls).length === 0) {
if (addToSeen(this.classesWithNodesInsertedAtStart, getNodeId(cls), { node: cls, sourceFile })) {
// For `class C {\n}`, don't add the trailing "\n"
const shouldSuffix = (positionsAreOnSameLine as any)(...getClassBraceEnds(cls, sourceFile), sourceFile); // TODO: GH#4130 remove 'as any'
return { prefix: this.newLineCharacter, suffix: shouldSuffix ? this.newLineCharacter : "" };
const shouldSuffix = (positionsAreOnSameLine as any)(...getClassOrObjectBraceEnds(cls, sourceFile), sourceFile); // TODO: GH#4130 remove 'as any'
return { prefix: this.newLineCharacter, suffix: comma + (shouldSuffix ? this.newLineCharacter : "") };
}
else {
return { prefix: "", suffix: this.newLineCharacter };
return { prefix: "", suffix: comma + this.newLineCharacter };
}
}
else {
return { prefix: this.newLineCharacter, suffix: "" };
return { prefix: this.newLineCharacter, suffix: comma };
}
}
@@ -647,9 +655,8 @@ namespace ts.textChanges {
}
private finishClassesWithNodesInsertedAtStart(): void {
this.classesWithNodesInsertedAtStart.forEach(cls => {
const sourceFile = cls.getSourceFile();
const [openBraceEnd, closeBraceEnd] = getClassBraceEnds(cls, sourceFile);
this.classesWithNodesInsertedAtStart.forEach(({ node, sourceFile }) => {
const [openBraceEnd, closeBraceEnd] = getClassOrObjectBraceEnds(node, sourceFile);
// For `class C { }` remove the whitespace inside the braces.
if (positionsAreOnSameLine(openBraceEnd, closeBraceEnd, sourceFile) && openBraceEnd !== closeBraceEnd - 1) {
this.deleteRange(sourceFile, createRange(openBraceEnd, closeBraceEnd - 1));
@@ -698,7 +705,7 @@ namespace ts.textChanges {
return changes;
}
public createNewFile(oldFile: SourceFile, fileName: string, statements: ReadonlyArray<Statement>) {
public createNewFile(oldFile: SourceFile | undefined, fileName: string, statements: ReadonlyArray<Statement>) {
this.newFiles.push({ oldFile, fileName, statements });
}
}
@@ -708,12 +715,19 @@ namespace ts.textChanges {
return skipTrivia(sourceFile.text, getAdjustedStartPosition(sourceFile, node, {}, Position.FullStart), /*stopAfterLineBreak*/ false, /*stopAtComments*/ true);
}
function getClassBraceEnds(cls: ClassLikeDeclaration | InterfaceDeclaration, sourceFile: SourceFile): [number, number] {
function getClassOrObjectBraceEnds(cls: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression, sourceFile: SourceFile): [number, number] {
return [findChildOfKind(cls, SyntaxKind.OpenBraceToken, sourceFile)!.end, findChildOfKind(cls, SyntaxKind.CloseBraceToken, sourceFile)!.end];
}
function getMembersOrProperties(cls: ClassLikeDeclaration | InterfaceDeclaration | ObjectLiteralExpression): NodeArray<Node> {
return isObjectLiteralExpression(cls) ? cls.properties : cls.members;
}
export type ValidateNonFormattedText = (node: Node, text: string) => void;
export function getNewFileText(statements: ReadonlyArray<Statement>, scriptKind: ScriptKind, newLineCharacter: string, formatContext: formatting.FormatContext): string {
return changesToText.newFileChangesWorker(/*oldFile*/ undefined, scriptKind, statements, newLineCharacter, formatContext);
}
namespace changesToText {
export function getTextChangesFromChanges(changes: ReadonlyArray<Change>, newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText | undefined): FileTextChanges[] {
return group(changes, c => c.sourceFile.path).map(changesInFile => {
@@ -732,13 +746,17 @@ namespace ts.textChanges {
});
}
export function newFileChanges(oldFile: SourceFile, fileName: string, statements: ReadonlyArray<Statement>, newLineCharacter: string, formatContext: formatting.FormatContext): FileTextChanges {
export function newFileChanges(oldFile: SourceFile | undefined, fileName: string, statements: ReadonlyArray<Statement>, newLineCharacter: string, formatContext: formatting.FormatContext): FileTextChanges {
const text = newFileChangesWorker(oldFile, getScriptKindFromFileName(fileName), statements, newLineCharacter, formatContext);
return { fileName, textChanges: [createTextChange(createTextSpan(0, 0), text)], isNewFile: true };
}
export function newFileChangesWorker(oldFile: SourceFile | undefined, scriptKind: ScriptKind, statements: ReadonlyArray<Statement>, newLineCharacter: string, formatContext: formatting.FormatContext): string {
// TODO: this emits the file, parses it back, then formats it that -- may be a less roundabout way to do this
const nonFormattedText = statements.map(s => getNonformattedText(s, oldFile, newLineCharacter).text).join(newLineCharacter);
const sourceFile = createSourceFile(fileName, nonFormattedText, ScriptTarget.ESNext, /*setParentNodes*/ true);
const sourceFile = createSourceFile("any file name", nonFormattedText, ScriptTarget.ESNext, /*setParentNodes*/ true, scriptKind);
const changes = formatting.formatDocument(sourceFile, formatContext);
const text = applyChanges(nonFormattedText, changes);
return { fileName, textChanges: [createTextChange(createTextSpan(0, 0), text)], isNewFile: true };
return applyChanges(nonFormattedText, changes);
}
function computeNewText(change: Change, sourceFile: SourceFile, newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText | undefined): string {
@@ -781,7 +799,7 @@ namespace ts.textChanges {
function getNonformattedText(node: Node, sourceFile: SourceFile | undefined, newLineCharacter: string): { text: string, node: Node } {
const writer = new Writer(newLineCharacter);
const newLine = newLineCharacter === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed;
createPrinter({ newLine }, writer).writeNode(EmitHint.Unspecified, node, sourceFile, writer);
createPrinter({ newLine, neverAsciiEscape: true }, writer).writeNode(EmitHint.Unspecified, node, sourceFile, writer);
return { text: writer.getText(), node: assignPositionsToNode(node) };
}
}
+2 -1
View File
@@ -70,6 +70,7 @@
"codefixes/inferFromUsage.ts",
"codefixes/fixInvalidImportSyntax.ts",
"codefixes/fixStrictClassInitialization.ts",
"codefixes/generateTypes.ts",
"codefixes/requireInTs.ts",
"codefixes/useDefaultImport.ts",
"codefixes/fixAddModuleReferTypeMissingTypeof.ts",
@@ -83,6 +84,6 @@
"services.ts",
"breakpoints.ts",
"transform.ts",
"shims.ts"
"shims.ts",
]
}
+44 -7
View File
@@ -231,6 +231,8 @@ namespace ts {
isKnownTypesPackageName?(name: string): boolean;
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
/* @internal */ inspectValue?(options: InspectValueOptions): Promise<ValueInfo>;
writeFile?(fileName: string, content: string): void;
}
/* @internal */
@@ -331,9 +333,9 @@ namespace ts {
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: ReadonlyArray<number>, formatOptions: FormatCodeSettings, preferences: UserPreferences): ReadonlyArray<CodeFixAction>;
getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences): CombinedCodeActions;
applyCodeActionCommand(action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
applyCodeActionCommand(action: CodeActionCommand[]): Promise<ApplyCodeActionCommandResult[]>;
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[]): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult>;
applyCodeActionCommand(action: CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult[]>;
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
/** @deprecated `fileName` will be ignored */
applyCodeActionCommand(fileName: string, action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
/** @deprecated `fileName` will be ignored */
@@ -526,12 +528,22 @@ namespace ts {
// Publicly, this type is just `{}`. Internally it is a union of all the actions we use.
// See `commands?: {}[]` in protocol.ts
export type CodeActionCommand = InstallPackageAction;
export type CodeActionCommand = InstallPackageAction | GenerateTypesAction;
export interface InstallPackageAction {
/* @internal */ file: string;
/* @internal */ type: "install package";
/* @internal */ packageName: string;
/* @internal */ readonly type: "install package";
/* @internal */ readonly file: string;
/* @internal */ readonly packageName: string;
}
export interface GenerateTypesAction extends GenerateTypesOptions {
/* @internal */ readonly type: "generate types";
}
export interface GenerateTypesOptions {
readonly file: string; // File that was importing fileToGenerateTypesFor; used for formatting options.
readonly fileToGenerateTypesFor: string;
readonly outputFileName: string;
}
/**
@@ -717,6 +729,31 @@ namespace ts {
indentMultiLineObjectLiteralBeginningOnBlankLine?: boolean;
}
/* @internal */
export const testFormatSettings: FormatCodeSettings = {
baseIndentSize: 0,
indentSize: 4,
tabSize: 4,
newLineCharacter: "\n",
convertTabsToSpaces: true,
indentStyle: IndentStyle.Smart,
insertSpaceAfterCommaDelimiter: true,
insertSpaceAfterSemicolonInForStatements: true,
insertSpaceBeforeAndAfterBinaryOperators: true,
insertSpaceAfterConstructor: false,
insertSpaceAfterKeywordsInControlFlowStatements: true,
insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
insertSpaceAfterTypeAssertion: false,
placeOpenBraceOnNewLineForFunctions: false,
placeOpenBraceOnNewLineForControlBlocks: false,
insertSpaceBeforeTypeAnnotation: false
};
export interface DefinitionInfo extends DocumentSpan {
kind: ScriptElementKind;
name: string;
@@ -244,6 +244,20 @@ namespace ts {
}, [
combinePaths(basePath, "main.ts")
]);
it("adds extendedSourceFiles only once", () => {
const sourceFile = readJsonConfigFile("configs/fourth.json", (path) => host.readFile(path));
const dir = combinePaths(basePath, "configs");
const expected = [
combinePaths(dir, "third.json"),
combinePaths(dir, "second.json"),
combinePaths(dir, "base.json"),
];
parseJsonSourceFileConfigFileContent(sourceFile, host, dir, {}, "fourth.json");
assert.deepEqual(sourceFile.extendedSourceFiles, expected);
parseJsonSourceFileConfigFileContent(sourceFile, host, dir, {}, "fourth.json");
assert.deepEqual(sourceFile.extendedSourceFiles, expected);
});
});
});
});
@@ -292,7 +292,7 @@ interface Array<T> {}`
cancellationToken: { throwIfCancellationRequested: noop, isCancellationRequested: returnFalse },
preferences: emptyOptions,
host: notImplementedHost,
formatContext: formatting.getFormatContext(testFormatOptions)
formatContext: formatting.getFormatContext(testFormatSettings)
};
const diagnostics = languageService.getSuggestionDiagnostics(f.path);
@@ -416,6 +416,20 @@ function [#|f|](): Promise<void> {
return fetch('https://typescriptlang.org').then( () => console.log("done") );
}`
);
_testConvertToAsyncFunction("convertToAsyncFunction_IgnoreArgs3", `
function [#|f|](): Promise<void> {
return fetch('https://typescriptlang.org').then( () => console.log("almost done") ).then( () => console.log("done") );
}`
);
_testConvertToAsyncFunction("convertToAsyncFunction_IgnoreArgs4", `
function [#|f|]() {
return fetch('https://typescriptlang.org').then(res);
}
function res(){
console.log("done");
}`
);
_testConvertToAsyncFunction("convertToAsyncFunction_Method", `
class Parser {
[#|f|]():Promise<void> {
@@ -473,6 +487,12 @@ function [#|f|]():Promise<void | Response> {
function [#|f|]() {
return fetch('https://typescriptlang.org').then(undefined, rejection => console.log("rejected:", rejection));
}
`
);
_testConvertToAsyncFunction("convertToAsyncFunction_NoCatchHandler", `
function [#|f|]() {
return fetch('https://typescriptlang.org').then(x => x.statusText).catch(undefined);
}
`
);
_testConvertToAsyncFunctionFailed("convertToAsyncFunction_NoSuggestion", `
@@ -817,7 +837,7 @@ function [#|f|]() {
);
_testConvertToAsyncFunction("convertToAsyncFunction_Scope1", `
function [#|f|]() {
var var1:Promise<Response>, var2;
var var1: Response, var2;
return fetch('https://typescriptlang.org').then( _ =>
Promise.resolve().then( res => {
var2 = "test";
@@ -1183,6 +1203,45 @@ function [#|f|]() {
}
`);
_testConvertToAsyncFunction("convertToAsyncFunction_runEffectfulContinuation", `
function [#|f|]() {
return fetch('https://typescriptlang.org').then(res).then(_ => console.log("done"));
}
function res(result) {
return Promise.resolve().then(x => console.log(result));
}
`);
_testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsPromise", `
function [#|f|]() {
return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText.length)).then(x => console.log(x + 5));
}
`);
_testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsPromiseInBlock", `
function [#|f|]() {
return fetch('https://typescriptlang.org').then(s => { return Promise.resolve(s.statusText.length) }).then(x => x + 5);
}
`);
_testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsFixablePromise", `
function [#|f|]() {
return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText).then(st => st.length)).then(x => console.log(x + 5));
}
`);
_testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsPromiseLastInChain", `
function [#|f|]() {
return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText.length));
}
`);
_testConvertToAsyncFunction("convertToAsyncFunction_nestedPromises", `
function [#|f|]() {
return fetch('https://typescriptlang.org').then(x => Promise.resolve(3).then(y => Promise.resolve(x.statusText.length + y)));
}
`);
});
function _testConvertToAsyncFunction(caption: string, text: string) {
+2 -23
View File
@@ -64,27 +64,6 @@ namespace ts {
}
export const newLineCharacter = "\n";
export const testFormatOptions: FormatCodeSettings = {
indentSize: 4,
tabSize: 4,
newLineCharacter,
convertTabsToSpaces: true,
indentStyle: IndentStyle.Smart,
insertSpaceAfterConstructor: false,
insertSpaceAfterCommaDelimiter: true,
insertSpaceAfterSemicolonInForStatements: true,
insertSpaceBeforeAndAfterBinaryOperators: true,
insertSpaceAfterKeywordsInControlFlowStatements: true,
insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
insertSpaceBeforeFunctionParenthesis: false,
placeOpenBraceOnNewLineForFunctions: false,
placeOpenBraceOnNewLineForControlBlocks: false,
};
export const notImplementedHost: LanguageServiceHost = {
getCompilationSettings: notImplemented,
@@ -123,7 +102,7 @@ namespace ts {
startPosition: selectionRange.pos,
endPosition: selectionRange.end,
host: notImplementedHost,
formatContext: formatting.getFormatContext(testFormatOptions),
formatContext: formatting.getFormatContext(testFormatSettings),
preferences: emptyOptions,
};
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromRange(selectionRange));
@@ -185,7 +164,7 @@ namespace ts {
startPosition: selectionRange.pos,
endPosition: selectionRange.end,
host: notImplementedHost,
formatContext: formatting.getFormatContext(testFormatOptions),
formatContext: formatting.getFormatContext(testFormatSettings),
preferences: emptyOptions,
};
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromRange(selectionRange));
+2 -2
View File
@@ -270,7 +270,7 @@ export const Other = 1;
content: "function F() { }",
};
const languageService = makeLanguageService(testFile);
const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, testFormatOptions, emptyOptions);
const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, testFormatSettings, emptyOptions);
assert.isEmpty(changes);
});
@@ -741,7 +741,7 @@ export * from "lib";
function runBaseline(baselinePath: string, testFile: TestFSWithWatch.File, ...otherFiles: TestFSWithWatch.File[]) {
const { path: testPath, content: testContent } = testFile;
const languageService = makeLanguageService(testFile, ...otherFiles);
const changes = languageService.organizeImports({ type: "file", fileName: testPath }, testFormatOptions, emptyOptions);
const changes = languageService.organizeImports({ type: "file", fileName: testPath }, testFormatSettings, emptyOptions);
assert.equal(changes.length, 1);
assert.equal(changes[0].fileName, testPath);
@@ -305,10 +305,10 @@ namespace ts {
assert.equal(program1.structureIsReused, StructureIsReused.Not);
});
it("fails if rootdir changes", () => {
it("succeeds if rootdir changes", () => {
const program1 = newProgram(files, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/b" });
updateProgram(program1, ["a.ts"], { target, module: ModuleKind.CommonJS, rootDir: "/a/c" }, noop);
assert.equal(program1.structureIsReused, StructureIsReused.Not);
assert.equal(program1.structureIsReused, StructureIsReused.Completely);
});
it("fails if config path changes", () => {
+1 -1
View File
@@ -20,7 +20,7 @@ namespace ts {
const newLineCharacter = getNewLineCharacter(printerOptions);
function getRuleProvider(placeOpenBraceOnNewLineForFunctions: boolean): formatting.FormatContext {
return formatting.getFormatContext(placeOpenBraceOnNewLineForFunctions ? { ...testFormatOptions, placeOpenBraceOnNewLineForFunctions: true } : testFormatOptions);
return formatting.getFormatContext(placeOpenBraceOnNewLineForFunctions ? { ...testFormatSettings, placeOpenBraceOnNewLineForFunctions: true } : testFormatSettings);
}
// validate that positions that were recovered from the printed text actually match positions that will be created if the same text is parsed.
+107 -8
View File
@@ -34,6 +34,10 @@ namespace ts.tscWatch {
return `${projectPath(subProject)}/${baseFileName.toLowerCase()}`;
}
function projectFileName(subProject: SubProject, baseFileName: string) {
return `${projectPath(subProject)}/${baseFileName}`;
}
function projectFile(subProject: SubProject, baseFileName: string): File {
return {
path: projectFilePath(subProject, baseFileName),
@@ -94,6 +98,7 @@ namespace ts.tscWatch {
const ui = subProjectFiles(SubProject.ui);
const allFiles: ReadonlyArray<File> = [libFile, ...core, ...logic, ...tests, ...ui];
const testProjectExpectedWatchedFiles = [core[0], core[1], core[2], ...logic, ...tests].map(f => f.path);
const testProjectExpectedWatchedDirectoriesRecursive = [projectPath(SubProject.core), projectPath(SubProject.logic)];
function createSolutionInWatchMode(allFiles: ReadonlyArray<File>, defaultOptions?: BuildOptions, disableConsoleClears?: boolean) {
const host = createWatchedSystem(allFiles, { currentDirectory: projectsLocation });
@@ -110,7 +115,7 @@ namespace ts.tscWatch {
function verifyWatches(host: WatchedSystem) {
checkWatchedFiles(host, testProjectExpectedWatchedFiles);
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
checkWatchedDirectories(host, [projectPath(SubProject.core), projectPath(SubProject.logic)], /*recursive*/ true);
checkWatchedDirectories(host, testProjectExpectedWatchedDirectoriesRecursive, /*recursive*/ true);
}
it("creates solution in watch mode", () => {
@@ -161,7 +166,7 @@ namespace ts.tscWatch {
function verifyWatches() {
checkWatchedFiles(host, additionalFiles ? testProjectExpectedWatchedFiles.concat(newFile.path) : testProjectExpectedWatchedFiles);
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
checkWatchedDirectories(host, [projectPath(SubProject.core), projectPath(SubProject.logic)], /*recursive*/ true);
checkWatchedDirectories(host, testProjectExpectedWatchedDirectoriesRecursive, /*recursive*/ true);
}
}
@@ -347,7 +352,7 @@ function myFunc() { return 100; }`);
function verifyWatches() {
checkWatchedFiles(host, projectFiles.map(f => f.path));
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
checkWatchedDirectories(host, [projectPath(SubProject.core), projectPath(SubProject.logic)], /*recursive*/ true);
checkWatchedDirectories(host, testProjectExpectedWatchedDirectoriesRecursive, /*recursive*/ true);
}
});
@@ -389,12 +394,106 @@ let x: string = 10;`);
});
});
it("tsc-watch works with project references", () => {
// Build the composite project
const host = createSolutionInWatchMode(allFiles);
describe("tsc-watch works with project references", () => {
const coreIndexDts = projectFileName(SubProject.core, "index.d.ts");
const coreAnotherModuleDts = projectFileName(SubProject.core, "anotherModule.d.ts");
const logicIndexDts = projectFileName(SubProject.logic, "index.d.ts");
const expectedWatchedFiles = [core[0], logic[0], ...tests, libFile].map(f => f.path).concat([coreIndexDts, coreAnotherModuleDts, logicIndexDts].map(f => f.toLowerCase()));
const expectedWatchedDirectoriesRecursive = projectSystem.getTypeRootsFromLocation(projectPath(SubProject.tests));
createWatchOfConfigFile(tests[0].path, host);
checkOutputErrorsInitial(host, emptyArray);
function createSolution() {
const host = createWatchedSystem(allFiles, { currentDirectory: projectsLocation });
const solutionBuilder = createSolutionBuilder(host, [`${project}/${SubProject.tests}`], {});
return { host, solutionBuilder };
}
function createBuiltSolution() {
const result = createSolution();
const { host, solutionBuilder } = result;
solutionBuilder.buildAllProjects();
const outputFileStamps = getOutputFileStamps(host);
for (const stamp of outputFileStamps) {
assert.isDefined(stamp[1], `${stamp[0]} expected to be present`);
}
return result;
}
function verifyWatches(host: WatchedSystem) {
checkWatchedFilesDetailed(host, expectedWatchedFiles, 1);
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
checkWatchedDirectoriesDetailed(host, expectedWatchedDirectoriesRecursive, 1, /*recursive*/ true);
}
function createSolutionAndWatchMode() {
// Build the composite project
const { host, solutionBuilder } = createBuiltSolution();
// Build in watch mode
const watch = createWatchOfConfigFileReturningBuilder(tests[0].path, host);
checkOutputErrorsInitial(host, emptyArray);
return { host, solutionBuilder, watch };
}
function verifyDependencies(watch: () => BuilderProgram, filePath: string, expected: ReadonlyArray<string>) {
checkArray(`${filePath} dependencies`, watch().getAllDependencies(watch().getSourceFile(filePath)!), expected);
}
describe("invoking when references are already built", () => {
it("verifies dependencies and watches", () => {
const { host, watch } = createSolutionAndWatchMode();
verifyWatches(host);
verifyDependencies(watch, coreIndexDts, [coreIndexDts]);
verifyDependencies(watch, coreAnotherModuleDts, [coreAnotherModuleDts]);
verifyDependencies(watch, logicIndexDts, [logicIndexDts, coreAnotherModuleDts]);
verifyDependencies(watch, tests[1].path, [tests[1].path, coreAnotherModuleDts, logicIndexDts, coreAnotherModuleDts]);
});
it("local edit in ts file, result in watch compilation because logic.d.ts is written", () => {
const { host, solutionBuilder, watch } = createSolutionAndWatchMode();
host.writeFile(logic[1].path, `${logic[1].content}
function foo() {
}`);
solutionBuilder.invalidateProject(`${project}/${SubProject.logic}`);
solutionBuilder.buildInvalidatedProject();
host.checkTimeoutQueueLengthAndRun(1); // not ideal, but currently because of d.ts but no new file is written
checkOutputErrorsIncremental(host, emptyArray);
checkProgramActualFiles(watch().getProgram(), [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, logicIndexDts]);
});
it("non local edit in ts file, rebuilds in watch compilation", () => {
const { host, solutionBuilder, watch } = createSolutionAndWatchMode();
host.writeFile(logic[1].path, `${logic[1].content}
export function gfoo() {
}`);
solutionBuilder.invalidateProject(logic[0].path);
solutionBuilder.buildInvalidatedProject();
host.checkTimeoutQueueLengthAndRun(1);
checkOutputErrorsIncremental(host, emptyArray);
checkProgramActualFiles(watch().getProgram(), [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, logicIndexDts]);
});
it("change in project reference config file builds correctly", () => {
const { host, solutionBuilder, watch } = createSolutionAndWatchMode();
host.writeFile(logic[0].path, JSON.stringify({
compilerOptions: { composite: true, declaration: true, declarationDir: "decls" },
references: [{ path: "../core" }]
}));
solutionBuilder.invalidateProject(logic[0].path, ConfigFileProgramReloadLevel.Full);
solutionBuilder.buildInvalidatedProject();
host.checkTimeoutQueueLengthAndRun(1);
checkOutputErrorsIncremental(host, [
// TODO: #26036
// The error is reported in d.ts file because it isnt resolved from ts file path, but is resolved from .d.ts file
"sample1/logic/decls/index.d.ts(2,22): error TS2307: Cannot find module '../core/anotherModule'.\n"
]);
checkProgramActualFiles(watch().getProgram(), [tests[1].path, libFile.path, coreIndexDts, coreAnotherModuleDts, projectFilePath(SubProject.logic, "decls/index.d.ts")]);
});
});
});
});
}
+39 -11
View File
@@ -20,6 +20,13 @@ namespace ts.tscWatch {
checkArray(`Program rootFileNames`, program.getRootFileNames(), expectedFiles);
}
export function createWatchOfConfigFileReturningBuilder(configFileName: string, host: WatchedSystem, maxNumberOfFilesToIterateForInvalidation?: number) {
const compilerHost = createWatchCompilerHostOfConfigFile(configFileName, {}, host);
compilerHost.maxNumberOfFilesToIterateForInvalidation = maxNumberOfFilesToIterateForInvalidation;
const watch = createWatchProgram(compilerHost);
return () => watch.getCurrentProgram();
}
export function createWatchOfConfigFile(configFileName: string, host: WatchedSystem, maxNumberOfFilesToIterateForInvalidation?: number) {
const compilerHost = createWatchCompilerHostOfConfigFile(configFileName, {}, host);
compilerHost.maxNumberOfFilesToIterateForInvalidation = maxNumberOfFilesToIterateForInvalidation;
@@ -443,6 +450,33 @@ namespace ts.tscWatch {
checkOutputErrorsIncremental(host, emptyArray);
});
it("Updates diagnostics when '--noUnusedLabels' changes", () => {
const aTs: File = { path: "/a.ts", content: "label: while (1) {}" };
const files = [libFile, aTs];
const paths = files.map(f => f.path);
const options = (allowUnusedLabels: boolean) => `{ "compilerOptions": { "allowUnusedLabels": ${allowUnusedLabels} } }`;
const tsconfig: File = { path: "/tsconfig.json", content: options(/*allowUnusedLabels*/ true) };
const host = createWatchedSystem([...files, tsconfig]);
const watch = createWatchOfConfigFile(tsconfig.path, host);
checkProgramActualFiles(watch(), paths);
checkOutputErrorsInitial(host, emptyArray);
host.modifyFile(tsconfig.path, options(/*allowUnusedLabels*/ false));
host.checkTimeoutQueueLengthAndRun(1); // reload the configured project
checkProgramActualFiles(watch(), paths);
checkOutputErrorsIncremental(host, [
getDiagnosticOfFileFromProgram(watch(), aTs.path, 0, "label".length, Diagnostics.Unused_label),
]);
host.modifyFile(tsconfig.path, options(/*allowUnusedLabels*/ true));
host.checkTimeoutQueueLengthAndRun(1); // reload the configured project
checkProgramActualFiles(watch(), paths);
checkOutputErrorsIncremental(host, emptyArray);
});
it("files explicitly excluded in config file", () => {
const configFile: File = {
path: "/a/b/tsconfig.json",
@@ -1190,7 +1224,7 @@ namespace ts.tscWatch {
host.reloadFS(files);
host.runQueuedTimeoutCallbacks();
checkProgramActualFiles(watch(), files.map(file => file.path));
checkOutputErrorsIncremental(host, []);
checkOutputErrorsIncremental(host, emptyArray);
});
it("watched files when file is deleted and new file is added as part of change", () => {
@@ -1322,12 +1356,10 @@ export class B
path: `${currentDirectory}/a.ts`,
content: `declare function foo(): null | { hello: any };
foo().hello`
};
const compilerOptions: CompilerOptions = {
};
const config: File = {
path: `${currentDirectory}/tsconfig.json`,
content: JSON.stringify({ compilerOptions })
content: JSON.stringify({ compilerOptions: {} })
};
const files = [aFile, config, libFile];
const host = createWatchedSystem(files, { currentDirectory });
@@ -1335,8 +1367,7 @@ foo().hello`
checkProgramActualFiles(watch(), [aFile.path, libFile.path]);
checkOutputErrorsInitial(host, emptyArray);
const modifiedTimeOfAJs = host.getModifiedTime(`${currentDirectory}/a.js`);
compilerOptions.strictNullChecks = true;
host.writeFile(config.path, JSON.stringify({ compilerOptions }));
host.writeFile(config.path, JSON.stringify({ compilerOptions: { strictNullChecks: true } }));
host.runQueuedTimeoutCallbacks();
const expectedStrictNullErrors = [
getDiagnosticOfFileFromProgram(watch(), aFile.path, aFile.content.lastIndexOf("foo()"), 5, Diagnostics.Object_is_possibly_null)
@@ -1344,15 +1375,12 @@ foo().hello`
checkOutputErrorsIncremental(host, expectedStrictNullErrors);
// File a need not be rewritten
assert.equal(host.getModifiedTime(`${currentDirectory}/a.js`), modifiedTimeOfAJs);
compilerOptions.strict = true;
delete (compilerOptions.strictNullChecks);
host.writeFile(config.path, JSON.stringify({ compilerOptions }));
host.writeFile(config.path, JSON.stringify({ compilerOptions: { strict: true, alwaysStrict: false } })); // Avoid changing 'alwaysStrict' or must re-bind
host.runQueuedTimeoutCallbacks();
checkOutputErrorsIncremental(host, expectedStrictNullErrors);
// File a need not be rewritten
assert.equal(host.getModifiedTime(`${currentDirectory}/a.js`), modifiedTimeOfAJs);
delete (compilerOptions.strict);
host.writeFile(config.path, JSON.stringify({ compilerOptions }));
host.writeFile(config.path, JSON.stringify({ compilerOptions: {} }));
host.runQueuedTimeoutCallbacks();
checkOutputErrorsIncremental(host, emptyArray);
// File a need not be rewritten
+109 -12
View File
@@ -85,6 +85,7 @@ namespace ts.projectSystem {
isKnownTypesPackageName = notImplemented;
installPackage = notImplemented;
inspectValue = notImplemented;
executePendingCommands() {
const actionsToRun = this.postExecActions;
@@ -456,7 +457,7 @@ namespace ts.projectSystem {
function protocolFileLocationFromSubstring(file: File, substring: string): protocol.FileLocationRequestArgs {
return { file: file.path, ...protocolLocationFromSubstring(file.content, substring) };
}
function protocolFileSpanFromSubstring(file: File, substring: string, options?: SpanFromSubstringOptions) {
function protocolFileSpanFromSubstring(file: File, substring: string, options?: SpanFromSubstringOptions): protocol.FileSpan {
return { file: file.path, ...protocolTextSpanFromSubstring(file.content, substring, options) };
}
function documentSpanFromSubstring(file: File, substring: string, options?: SpanFromSubstringOptions): DocumentSpan {
@@ -3491,7 +3492,7 @@ namespace ts.projectSystem {
host.checkTimeoutQueueLength(2); // Update configured project and projects for open file
checkProjectActualFiles(services.configuredProjects.get(config.path)!, filesWithFileA.map(f => f.path));
// host.fileExists = originalFileExists;
// host.fileExists = originalFileExists;
openFile(fileSubA);
// This should create inferred project since fileSubA not on the disk
checkProjectActualFiles(services.configuredProjects.get(config.path)!, mapDefined(filesWithFileA, f => f === fileA ? undefined : f.path));
@@ -3672,7 +3673,7 @@ namespace ts.projectSystem {
path: `${projectRoot}/app1/tsconfig.json`,
content: JSON.stringify({
files: ["app.ts", "../core/core.ts"],
compilerOptions: { outFile : "build/output.js" },
compilerOptions: { outFile: "build/output.js" },
compileOnSave: true
})
};
@@ -6778,9 +6779,9 @@ namespace ts.projectSystem {
fileName: "/a.1.ts",
textChanges: [
{
start: { line: 0, offset: 0 },
end: { line: 0, offset: 0 },
newText: "export const a = 0;",
start: { line: 0, offset: 0 },
end: { line: 0, offset: 0 },
newText: "export const a = 0;",
},
],
}
@@ -8287,7 +8288,8 @@ namespace ts.projectSystem {
protocolTextSpanFromSubstring(aFile.content, "C"),
protocolTextSpanFromSubstring(aFile.content, "C", { index: 1 }),
];
const cLocs: protocol.TextSpan[] = [protocolTextSpanFromSubstring(cFile.content, "C")];
const span = protocolTextSpanFromSubstring(cFile.content, "C");
const cLocs: protocol.TextSpan[] = [span];
assert.deepEqual<protocol.RenameResponseBody | undefined>(response, {
info: {
canRename: true,
@@ -8296,6 +8298,7 @@ namespace ts.projectSystem {
kind: ScriptElementKind.constElement,
kindModifiers: ScriptElementKindModifier.exportedModifier,
localizedErrorMessage: undefined,
triggerSpan: span,
},
locs: [
{ file: aFc, locs: cLocs },
@@ -8672,7 +8675,7 @@ new C();`
}));
checkWatchedDirectories(host, [], /*recursive*/ false);
checkWatchedDirectories(host, arrayFrom(expectedRecursiveDirectories.keys()), /*recursive*/ true);
}
}
describe("from files in same folder", () => {
function getFiles(fileContent: string) {
@@ -9090,7 +9093,7 @@ export const x = 10;`
Debug.assert(!!project.resolveModuleNames);
const edits = project.getLanguageService().getEditsForFileRename("/old.ts", "/new.ts", testFormatOptions, emptyOptions);
const edits = project.getLanguageService().getEditsForFileRename("/old.ts", "/new.ts", testFormatSettings, emptyOptions);
assert.deepEqual<ReadonlyArray<FileTextChanges>>(edits, [{
fileName: "/user.ts",
textChanges: [{
@@ -9750,7 +9753,7 @@ declare class TestLib {
function verifyATsConfigOriginalProject(session: TestSession) {
checkNumberOfProjects(session.getProjectService(), { inferredProjects: 1, configuredProjects: 1 });
verifyInferredProjectUnchanged(session);
verifyATsConfigProject(session);
verifyATsConfigProject(session);
// Close user file should close all the projects
closeFilesForSession([userTs], session);
verifyOnlyOrphanInferredProject(session);
@@ -9900,11 +9903,12 @@ declare class TestLib {
verifyATsConfigWhenOpened(session);
});
interface ReferencesFullRequest extends protocol.FileLocationRequest { readonly command: protocol.CommandTypes.ReferencesFull; }
interface ReferencesFullResponse extends protocol.Response { readonly body: ReadonlyArray<ReferencedSymbol>; }
it("findAllReferencesFull", () => {
const session = makeSampleProjects();
interface ReferencesFullRequest extends protocol.FileLocationRequest { command: protocol.CommandTypes.ReferencesFull; }
interface ReferencesFullResponse extends protocol.Response { body: ReadonlyArray<ReferencedSymbol>; }
const responseFull = executeSessionRequest<ReferencesFullRequest, ReferencesFullResponse>(session, protocol.CommandTypes.ReferencesFull, protocolFileLocationFromSubstring(userTs, "fnA()"));
function fnAVoid(kind: SymbolDisplayPartKind): SymbolDisplayPart[] {
@@ -9961,6 +9965,67 @@ declare class TestLib {
verifyATsConfigOriginalProject(session);
});
it("findAllReferencesFull definition is in mapped file", () => {
const aTs: File = { path: "/a/a.ts", content: `function f() {}` };
const aTsconfig: File = {
path: "/a/tsconfig.json",
content: JSON.stringify({ compilerOptions: { declaration: true, declarationMap: true, outFile: "../bin/a.js" } }),
};
const bTs: File = { path: "/b/b.ts", content: `f();` };
const bTsconfig: File = { path: "/b/tsconfig.json", content: JSON.stringify({ references: [{ path: "../a" }] }) };
const aDts: File = { path: "/bin/a.d.ts", content: `declare function f(): void;\n//# sourceMappingURL=a.d.ts.map` };
const aDtsMap: File = {
path: "/bin/a.d.ts.map",
content: JSON.stringify({ version: 3, file: "a.d.ts", sourceRoot: "", sources: ["../a/a.ts"], names: [], mappings: "AAAA,iBAAS,CAAC,SAAK" }),
};
const session = createSession(createServerHost([aTs, aTsconfig, bTs, bTsconfig, aDts, aDtsMap]));
checkDeclarationFiles(aTs, session, [aDtsMap, aDts]);
openFilesForSession([bTs], session);
checkNumberOfProjects(session.getProjectService(), { configuredProjects: 1 });
const responseFull = executeSessionRequest<ReferencesFullRequest, ReferencesFullResponse>(session, protocol.CommandTypes.ReferencesFull, protocolFileLocationFromSubstring(bTs, "f()"));
assert.deepEqual<ReadonlyArray<ReferencedSymbol>>(responseFull, [
{
definition: {
containerKind: ScriptElementKind.unknown,
containerName: "",
displayParts: [
keywordPart(SyntaxKind.FunctionKeyword),
spacePart(),
displayPart("f", SymbolDisplayPartKind.functionName),
punctuationPart(SyntaxKind.OpenParenToken),
punctuationPart(SyntaxKind.CloseParenToken),
punctuationPart(SyntaxKind.ColonToken),
spacePart(),
keywordPart(SyntaxKind.VoidKeyword),
],
fileName: aTs.path,
kind: ScriptElementKind.functionElement,
name: "function f(): void",
textSpan: { start: 9, length: 1 },
},
references: [
{
fileName: bTs.path,
isDefinition: false,
isInString: undefined,
isWriteAccess: false,
textSpan: { start: 0, length: 1 },
},
{
fileName: aTs.path,
isDefinition: true,
isInString: undefined,
isWriteAccess: true,
textSpan: { start: 9, length: 1 },
},
],
}
]);
});
it("findAllReferences -- target does not exist", () => {
const session = makeSampleProjects();
@@ -10001,6 +10066,7 @@ declare class TestLib {
kind: ScriptElementKind.alias,
kindModifiers: ScriptElementKindModifier.none,
localizedErrorMessage: undefined,
triggerSpan: protocolTextSpanFromSubstring(userTs.content, "fnA", { index: 1 }),
},
locs: [renameUserTs(userTs), renameATs(aTs)],
});
@@ -10019,6 +10085,7 @@ declare class TestLib {
kind: ScriptElementKind.functionElement,
kindModifiers: ScriptElementKindModifier.exportedModifier,
localizedErrorMessage: undefined,
triggerSpan: protocolTextSpanFromSubstring(aTs.content, "fnA"),
},
locs: [renameATs(aTs), renameUserTs(userTs)],
});
@@ -10047,6 +10114,7 @@ declare class TestLib {
kind: ScriptElementKind.alias,
kindModifiers: ScriptElementKindModifier.none,
localizedErrorMessage: undefined,
triggerSpan: protocolTextSpanFromSubstring(userTs.content, "fnB", { index: 1 }),
},
locs: [
{
@@ -10180,6 +10248,35 @@ declare class TestLib {
});
});
describe("tsserverProjectSystem config file change", () => {
it("Updates diagnostics when '--noUnusedLabels' changes", () => {
const aTs: File = { path: "/a.ts", content: "label: while (1) {}" };
const options = (allowUnusedLabels: boolean) => `{ "compilerOptions": { "allowUnusedLabels": ${allowUnusedLabels} } }`;
const tsconfig: File = { path: "/tsconfig.json", content: options(/*allowUnusedLabels*/ true) };
const host = createServerHost([aTs, tsconfig]);
const session = createSession(host);
openFilesForSession([aTs], session);
host.modifyFile(tsconfig.path, options(/*allowUnusedLabels*/ false));
host.runQueuedTimeoutCallbacks();
const response = executeSessionRequest<protocol.SemanticDiagnosticsSyncRequest, protocol.SemanticDiagnosticsSyncResponse>(session, protocol.CommandTypes.SemanticDiagnosticsSync, { file: aTs.path }) as protocol.Diagnostic[] | undefined;
assert.deepEqual<protocol.Diagnostic[] | undefined>(response, [
{
start: { line: 1, offset: 1 },
end: { line: 1, offset: 1 + "label".length },
text: "Unused label.",
category: "error",
code: Diagnostics.Unused_label.code,
relatedInformation: undefined,
reportsUnnecessary: true,
source: undefined,
},
]);
});
});
function makeReferenceItem(file: File, isDefinition: boolean, text: string, lineText: string, options?: SpanFromSubstringOptions): protocol.ReferencesResponseItem {
return {
...protocolFileSpanFromSubstring(file, text, options),
+16 -6
View File
@@ -231,7 +231,8 @@ namespace ts.server {
// buffer, but we have yet to find a way to retrieve that value.
private static readonly maxActiveRequestCount = 10;
private static readonly requestDelayMillis = 100;
private packageInstalledPromise: { resolve(value: ApplyCodeActionCommandResult): void, reject(reason: any): void } | undefined;
private packageInstalledPromise: { resolve(value: ApplyCodeActionCommandResult): void, reject(reason: unknown): void } | undefined;
private inspectValuePromise: { resolve(value: ValueInfo): void } | undefined;
constructor(
private readonly telemetryEnabled: boolean,
@@ -261,14 +262,19 @@ namespace ts.server {
}
installPackage(options: InstallPackageOptionsWithProject): Promise<ApplyCodeActionCommandResult> {
const rq: InstallPackageRequest = { kind: "installPackage", ...options };
this.send(rq);
this.send<InstallPackageRequest>({ kind: "installPackage", ...options });
Debug.assert(this.packageInstalledPromise === undefined);
return new Promise((resolve, reject) => {
return new Promise<ApplyCodeActionCommandResult>((resolve, reject) => {
this.packageInstalledPromise = { resolve, reject };
});
}
inspectValue(options: InspectValueOptions): Promise<ValueInfo> {
this.send<InspectValueRequest>({ kind: "inspectValue", options });
Debug.assert(this.inspectValuePromise === undefined);
return new Promise<ValueInfo>(resolve => { this.inspectValuePromise = { resolve }; });
}
attach(projectService: ProjectService) {
this.projectService = projectService;
if (this.logger.hasLevel(LogLevel.requestTime)) {
@@ -320,7 +326,7 @@ namespace ts.server {
this.send({ projectName: p.getProjectName(), kind: "closeProject" });
}
private send(rq: TypingInstallerRequestUnion): void {
private send<T extends TypingInstallerRequestUnion>(rq: T): void {
this.installer.send(rq);
}
@@ -353,7 +359,7 @@ namespace ts.server {
}
}
private handleMessage(response: TypesRegistryResponse | PackageInstalledResponse | SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes | InitializationFailedResponse) {
private handleMessage(response: TypesRegistryResponse | PackageInstalledResponse | InspectValueResponse | SetTypings | InvalidateCachedTypings | BeginInstallTypes | EndInstallTypes | InitializationFailedResponse) {
if (this.logger.hasLevel(LogLevel.verbose)) {
this.logger.info(`Received response:${stringifyIndented(response)}`);
}
@@ -378,6 +384,10 @@ namespace ts.server {
this.event(response, "setTypings");
break;
}
case ActionValueInspected:
this.inspectValuePromise!.resolve(response.result);
this.inspectValuePromise = undefined;
break;
case EventInitializationFailed:
{
const body: protocol.TypesInstallerInitializationFailedEventBody = {
@@ -164,6 +164,11 @@ namespace ts.server.typingsInstaller {
}
break;
}
case "inspectValue": {
const response: InspectValueResponse = { kind: ActionValueInspected, result: inspectModule(req.options.fileNameToRequire) };
this.sendResponse(response);
break;
}
default:
Debug.assertNever(req);
}
@@ -2,9 +2,10 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(4,24): error TS2715: Abstr
tests/cases/compiler/abstractPropertyInConstructor.ts(7,18): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
tests/cases/compiler/abstractPropertyInConstructor.ts(9,14): error TS2715: Abstract property 'cb' in class 'AbstractClass' cannot be accessed in the constructor.
tests/cases/compiler/abstractPropertyInConstructor.ts(25,18): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
tests/cases/compiler/abstractPropertyInConstructor.ts(39,22): error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
==== tests/cases/compiler/abstractPropertyInConstructor.ts (4 errors) ====
==== tests/cases/compiler/abstractPropertyInConstructor.ts (5 errors) ====
abstract class AbstractClass {
constructor(str: string, other: AbstractClass) {
this.method(parseInt(str));
@@ -45,6 +46,38 @@ tests/cases/compiler/abstractPropertyInConstructor.ts(25,18): error TS2715: Abst
}
}
abstract class DerivedAbstractClass extends AbstractClass {
cb = (s: string) => {};
constructor(str: string, other: AbstractClass, yetAnother: DerivedAbstractClass) {
super(str, other);
// there is no implementation of 'prop' in any base class
this.cb(this.prop.toLowerCase());
~~~~
!!! error TS2715: Abstract property 'prop' in class 'AbstractClass' cannot be accessed in the constructor.
this.method(1);
// OK, references are to another instance
other.cb(other.prop);
yetAnother.cb(yetAnother.prop);
}
}
class Implementation extends DerivedAbstractClass {
prop = "";
cb = (s: string) => {};
constructor(str: string, other: AbstractClass, yetAnother: DerivedAbstractClass) {
super(str, other, yetAnother);
this.cb(this.prop);
}
method(n: number) {
this.cb(this.prop + n);
}
}
class User {
constructor(a: AbstractClass) {
a.prop;
@@ -31,6 +31,36 @@ abstract class AbstractClass {
}
}
abstract class DerivedAbstractClass extends AbstractClass {
cb = (s: string) => {};
constructor(str: string, other: AbstractClass, yetAnother: DerivedAbstractClass) {
super(str, other);
// there is no implementation of 'prop' in any base class
this.cb(this.prop.toLowerCase());
this.method(1);
// OK, references are to another instance
other.cb(other.prop);
yetAnother.cb(yetAnother.prop);
}
}
class Implementation extends DerivedAbstractClass {
prop = "";
cb = (s: string) => {};
constructor(str: string, other: AbstractClass, yetAnother: DerivedAbstractClass) {
super(str, other, yetAnother);
this.cb(this.prop);
}
method(n: number) {
this.cb(this.prop + n);
}
}
class User {
constructor(a: AbstractClass) {
a.prop;
@@ -42,6 +72,19 @@ class User {
//// [abstractPropertyInConstructor.js]
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
}
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var AbstractClass = /** @class */ (function () {
function AbstractClass(str, other) {
var _this = this;
@@ -65,6 +108,35 @@ var AbstractClass = /** @class */ (function () {
};
return AbstractClass;
}());
var DerivedAbstractClass = /** @class */ (function (_super) {
__extends(DerivedAbstractClass, _super);
function DerivedAbstractClass(str, other, yetAnother) {
var _this = _super.call(this, str, other) || this;
_this.cb = function (s) { };
// there is no implementation of 'prop' in any base class
_this.cb(_this.prop.toLowerCase());
_this.method(1);
// OK, references are to another instance
other.cb(other.prop);
yetAnother.cb(yetAnother.prop);
return _this;
}
return DerivedAbstractClass;
}(AbstractClass));
var Implementation = /** @class */ (function (_super) {
__extends(Implementation, _super);
function Implementation(str, other, yetAnother) {
var _this = _super.call(this, str, other, yetAnother) || this;
_this.prop = "";
_this.cb = function (s) { };
_this.cb(_this.prop);
return _this;
}
Implementation.prototype.method = function (n) {
this.cb(this.prop + n);
};
return Implementation;
}(DerivedAbstractClass));
var User = /** @class */ (function () {
function User(a) {
a.prop;
@@ -92,31 +92,134 @@ abstract class AbstractClass {
}
}
abstract class DerivedAbstractClass extends AbstractClass {
>DerivedAbstractClass : Symbol(DerivedAbstractClass, Decl(abstractPropertyInConstructor.ts, 30, 1))
>AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
cb = (s: string) => {};
>cb : Symbol(DerivedAbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 32, 59))
>s : Symbol(s, Decl(abstractPropertyInConstructor.ts, 33, 10))
constructor(str: string, other: AbstractClass, yetAnother: DerivedAbstractClass) {
>str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 35, 16))
>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 35, 28))
>AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
>yetAnother : Symbol(yetAnother, Decl(abstractPropertyInConstructor.ts, 35, 50))
>DerivedAbstractClass : Symbol(DerivedAbstractClass, Decl(abstractPropertyInConstructor.ts, 30, 1))
super(str, other);
>super : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
>str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 35, 16))
>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 35, 28))
// there is no implementation of 'prop' in any base class
this.cb(this.prop.toLowerCase());
>this.cb : Symbol(DerivedAbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 32, 59))
>this : Symbol(DerivedAbstractClass, Decl(abstractPropertyInConstructor.ts, 30, 1))
>cb : Symbol(DerivedAbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 32, 59))
>this.prop.toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --))
>this.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
>this : Symbol(DerivedAbstractClass, Decl(abstractPropertyInConstructor.ts, 30, 1))
>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
>toLowerCase : Symbol(String.toLowerCase, Decl(lib.es5.d.ts, --, --))
this.method(1);
>this.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37))
>this : Symbol(DerivedAbstractClass, Decl(abstractPropertyInConstructor.ts, 30, 1))
>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37))
// OK, references are to another instance
other.cb(other.prop);
>other.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26))
>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 35, 28))
>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26))
>other.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 35, 28))
>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
yetAnother.cb(yetAnother.prop);
>yetAnother.cb : Symbol(DerivedAbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 32, 59))
>yetAnother : Symbol(yetAnother, Decl(abstractPropertyInConstructor.ts, 35, 50))
>cb : Symbol(DerivedAbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 32, 59))
>yetAnother.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
>yetAnother : Symbol(yetAnother, Decl(abstractPropertyInConstructor.ts, 35, 50))
>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
}
}
class Implementation extends DerivedAbstractClass {
>Implementation : Symbol(Implementation, Decl(abstractPropertyInConstructor.ts, 46, 1))
>DerivedAbstractClass : Symbol(DerivedAbstractClass, Decl(abstractPropertyInConstructor.ts, 30, 1))
prop = "";
>prop : Symbol(Implementation.prop, Decl(abstractPropertyInConstructor.ts, 48, 51))
cb = (s: string) => {};
>cb : Symbol(Implementation.cb, Decl(abstractPropertyInConstructor.ts, 49, 14))
>s : Symbol(s, Decl(abstractPropertyInConstructor.ts, 50, 10))
constructor(str: string, other: AbstractClass, yetAnother: DerivedAbstractClass) {
>str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 52, 16))
>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 52, 28))
>AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
>yetAnother : Symbol(yetAnother, Decl(abstractPropertyInConstructor.ts, 52, 50))
>DerivedAbstractClass : Symbol(DerivedAbstractClass, Decl(abstractPropertyInConstructor.ts, 30, 1))
super(str, other, yetAnother);
>super : Symbol(DerivedAbstractClass, Decl(abstractPropertyInConstructor.ts, 30, 1))
>str : Symbol(str, Decl(abstractPropertyInConstructor.ts, 52, 16))
>other : Symbol(other, Decl(abstractPropertyInConstructor.ts, 52, 28))
>yetAnother : Symbol(yetAnother, Decl(abstractPropertyInConstructor.ts, 52, 50))
this.cb(this.prop);
>this.cb : Symbol(Implementation.cb, Decl(abstractPropertyInConstructor.ts, 49, 14))
>this : Symbol(Implementation, Decl(abstractPropertyInConstructor.ts, 46, 1))
>cb : Symbol(Implementation.cb, Decl(abstractPropertyInConstructor.ts, 49, 14))
>this.prop : Symbol(Implementation.prop, Decl(abstractPropertyInConstructor.ts, 48, 51))
>this : Symbol(Implementation, Decl(abstractPropertyInConstructor.ts, 46, 1))
>prop : Symbol(Implementation.prop, Decl(abstractPropertyInConstructor.ts, 48, 51))
}
method(n: number) {
>method : Symbol(Implementation.method, Decl(abstractPropertyInConstructor.ts, 55, 5))
>n : Symbol(n, Decl(abstractPropertyInConstructor.ts, 57, 11))
this.cb(this.prop + n);
>this.cb : Symbol(Implementation.cb, Decl(abstractPropertyInConstructor.ts, 49, 14))
>this : Symbol(Implementation, Decl(abstractPropertyInConstructor.ts, 46, 1))
>cb : Symbol(Implementation.cb, Decl(abstractPropertyInConstructor.ts, 49, 14))
>this.prop : Symbol(Implementation.prop, Decl(abstractPropertyInConstructor.ts, 48, 51))
>this : Symbol(Implementation, Decl(abstractPropertyInConstructor.ts, 46, 1))
>prop : Symbol(Implementation.prop, Decl(abstractPropertyInConstructor.ts, 48, 51))
>n : Symbol(n, Decl(abstractPropertyInConstructor.ts, 57, 11))
}
}
class User {
>User : Symbol(User, Decl(abstractPropertyInConstructor.ts, 30, 1))
>User : Symbol(User, Decl(abstractPropertyInConstructor.ts, 60, 1))
constructor(a: AbstractClass) {
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 63, 16))
>AbstractClass : Symbol(AbstractClass, Decl(abstractPropertyInConstructor.ts, 0, 0))
a.prop;
>a.prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 63, 16))
>prop : Symbol(AbstractClass.prop, Decl(abstractPropertyInConstructor.ts, 17, 5))
a.cb("hi");
>a.cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26))
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 63, 16))
>cb : Symbol(AbstractClass.cb, Decl(abstractPropertyInConstructor.ts, 19, 26))
a.method(12);
>a.method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37))
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 63, 16))
>method : Symbol(AbstractClass.method, Decl(abstractPropertyInConstructor.ts, 20, 37))
a.method2();
>a.method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 25, 25))
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 33, 16))
>a : Symbol(a, Decl(abstractPropertyInConstructor.ts, 63, 16))
>method2 : Symbol(AbstractClass.method2, Decl(abstractPropertyInConstructor.ts, 25, 25))
}
}
@@ -104,6 +104,119 @@ abstract class AbstractClass {
}
}
abstract class DerivedAbstractClass extends AbstractClass {
>DerivedAbstractClass : DerivedAbstractClass
>AbstractClass : AbstractClass
cb = (s: string) => {};
>cb : (s: string) => void
>(s: string) => {} : (s: string) => void
>s : string
constructor(str: string, other: AbstractClass, yetAnother: DerivedAbstractClass) {
>str : string
>other : AbstractClass
>yetAnother : DerivedAbstractClass
super(str, other);
>super(str, other) : void
>super : typeof AbstractClass
>str : string
>other : AbstractClass
// there is no implementation of 'prop' in any base class
this.cb(this.prop.toLowerCase());
>this.cb(this.prop.toLowerCase()) : void
>this.cb : (s: string) => void
>this : this
>cb : (s: string) => void
>this.prop.toLowerCase() : string
>this.prop.toLowerCase : () => string
>this.prop : string
>this : this
>prop : string
>toLowerCase : () => string
this.method(1);
>this.method(1) : void
>this.method : (num: number) => void
>this : this
>method : (num: number) => void
>1 : 1
// OK, references are to another instance
other.cb(other.prop);
>other.cb(other.prop) : void
>other.cb : (s: string) => void
>other : AbstractClass
>cb : (s: string) => void
>other.prop : string
>other : AbstractClass
>prop : string
yetAnother.cb(yetAnother.prop);
>yetAnother.cb(yetAnother.prop) : void
>yetAnother.cb : (s: string) => void
>yetAnother : DerivedAbstractClass
>cb : (s: string) => void
>yetAnother.prop : string
>yetAnother : DerivedAbstractClass
>prop : string
}
}
class Implementation extends DerivedAbstractClass {
>Implementation : Implementation
>DerivedAbstractClass : DerivedAbstractClass
prop = "";
>prop : string
>"" : ""
cb = (s: string) => {};
>cb : (s: string) => void
>(s: string) => {} : (s: string) => void
>s : string
constructor(str: string, other: AbstractClass, yetAnother: DerivedAbstractClass) {
>str : string
>other : AbstractClass
>yetAnother : DerivedAbstractClass
super(str, other, yetAnother);
>super(str, other, yetAnother) : void
>super : typeof DerivedAbstractClass
>str : string
>other : AbstractClass
>yetAnother : DerivedAbstractClass
this.cb(this.prop);
>this.cb(this.prop) : void
>this.cb : (s: string) => void
>this : this
>cb : (s: string) => void
>this.prop : string
>this : this
>prop : string
}
method(n: number) {
>method : (n: number) => void
>n : number
this.cb(this.prop + n);
>this.cb(this.prop + n) : void
>this.cb : (s: string) => void
>this : this
>cb : (s: string) => void
>this.prop + n : string
>this.prop : string
>this : this
>prop : string
>n : number
}
}
class User {
>User : User
+18 -6
View File
@@ -4445,6 +4445,7 @@ declare namespace ts.server {
type ActionSet = "action::set";
type ActionInvalidate = "action::invalidate";
type ActionPackageInstalled = "action::packageInstalled";
type ActionValueInspected = "action::valueInspected";
type EventTypesRegistry = "event::typesRegistry";
type EventBeginInstallTypes = "event::beginInstallTypes";
type EventEndInstallTypes = "event::endInstallTypes";
@@ -4453,7 +4454,7 @@ declare namespace ts.server {
" __sortedArrayBrand": any;
}
interface TypingInstallerResponse {
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | ActionValueInspected | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
}
interface TypingInstallerRequestWithProjectName {
readonly projectName: string;
@@ -4661,6 +4662,7 @@ declare namespace ts {
getCustomTransformers?(): CustomTransformers | undefined;
isKnownTypesPackageName?(name: string): boolean;
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
writeFile?(fileName: string, content: string): void;
}
interface LanguageService {
cleanupSemanticCache(): void;
@@ -4718,9 +4720,9 @@ declare namespace ts {
toLineColumnOffset?(fileName: string, position: number): LineAndCharacter;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: ReadonlyArray<number>, formatOptions: FormatCodeSettings, preferences: UserPreferences): ReadonlyArray<CodeFixAction>;
getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences): CombinedCodeActions;
applyCodeActionCommand(action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
applyCodeActionCommand(action: CodeActionCommand[]): Promise<ApplyCodeActionCommandResult[]>;
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[]): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult>;
applyCodeActionCommand(action: CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult[]>;
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
/** @deprecated `fileName` will be ignored */
applyCodeActionCommand(fileName: string, action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
/** @deprecated `fileName` will be ignored */
@@ -4882,9 +4884,16 @@ declare namespace ts {
changes: ReadonlyArray<FileTextChanges>;
commands?: ReadonlyArray<CodeActionCommand>;
}
type CodeActionCommand = InstallPackageAction;
type CodeActionCommand = InstallPackageAction | GenerateTypesAction;
interface InstallPackageAction {
}
interface GenerateTypesAction extends GenerateTypesOptions {
}
interface GenerateTypesOptions {
readonly file: string;
readonly fileToGenerateTypesFor: string;
readonly outputFileName: string;
}
/**
* A set of one or more available refactoring actions, grouped under a parent refactoring.
*/
@@ -6455,6 +6464,8 @@ declare namespace ts.server.protocol {
* Optional modifiers for the kind (such as 'public').
*/
kindModifiers: string;
/** Span of text to rename. */
triggerSpan: TextSpan;
}
/**
* A group of text spans, all in 'file'.
@@ -8100,6 +8111,7 @@ declare namespace ts.server {
useCaseSensitiveFileNames(): boolean;
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
readFile(fileName: string): string | undefined;
writeFile(fileName: string, content: string): void;
fileExists(file: string): boolean;
resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModuleFull[];
getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string): ResolvedModuleWithFailedLookupLocations | undefined;
@@ -8733,7 +8745,7 @@ declare namespace ts.server {
private getProjects;
private getDefaultProject;
private getRenameLocations;
private static mapRenameInfo;
private mapRenameInfo;
private toSpanGroups;
private getReferences;
/**
+14 -5
View File
@@ -4445,6 +4445,7 @@ declare namespace ts.server {
type ActionSet = "action::set";
type ActionInvalidate = "action::invalidate";
type ActionPackageInstalled = "action::packageInstalled";
type ActionValueInspected = "action::valueInspected";
type EventTypesRegistry = "event::typesRegistry";
type EventBeginInstallTypes = "event::beginInstallTypes";
type EventEndInstallTypes = "event::endInstallTypes";
@@ -4453,7 +4454,7 @@ declare namespace ts.server {
" __sortedArrayBrand": any;
}
interface TypingInstallerResponse {
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | ActionValueInspected | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
}
interface TypingInstallerRequestWithProjectName {
readonly projectName: string;
@@ -4661,6 +4662,7 @@ declare namespace ts {
getCustomTransformers?(): CustomTransformers | undefined;
isKnownTypesPackageName?(name: string): boolean;
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
writeFile?(fileName: string, content: string): void;
}
interface LanguageService {
cleanupSemanticCache(): void;
@@ -4718,9 +4720,9 @@ declare namespace ts {
toLineColumnOffset?(fileName: string, position: number): LineAndCharacter;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: ReadonlyArray<number>, formatOptions: FormatCodeSettings, preferences: UserPreferences): ReadonlyArray<CodeFixAction>;
getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences): CombinedCodeActions;
applyCodeActionCommand(action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
applyCodeActionCommand(action: CodeActionCommand[]): Promise<ApplyCodeActionCommandResult[]>;
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[]): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult>;
applyCodeActionCommand(action: CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult[]>;
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
/** @deprecated `fileName` will be ignored */
applyCodeActionCommand(fileName: string, action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
/** @deprecated `fileName` will be ignored */
@@ -4882,9 +4884,16 @@ declare namespace ts {
changes: ReadonlyArray<FileTextChanges>;
commands?: ReadonlyArray<CodeActionCommand>;
}
type CodeActionCommand = InstallPackageAction;
type CodeActionCommand = InstallPackageAction | GenerateTypesAction;
interface InstallPackageAction {
}
interface GenerateTypesAction extends GenerateTypesOptions {
}
interface GenerateTypesOptions {
readonly file: string;
readonly fileToGenerateTypesFor: string;
readonly outputFileName: string;
}
/**
* A set of one or more available refactoring actions, grouped under a parent refactoring.
*/
@@ -1,14 +1,14 @@
tests/cases/compiler/arrayLiteralTypeInference.ts(14,14): error TS2322: Type '({ id: number; trueness: boolean; } | { id: number; name: string; })[]' is not assignable to type 'Action[]'.
Type '{ id: number; trueness: boolean; } | { id: number; name: string; }' is not assignable to type 'Action'.
Type '{ id: number; trueness: boolean; }' is not assignable to type 'Action'.
Object literal may only specify known properties, and 'trueness' does not exist in type 'Action'.
tests/cases/compiler/arrayLiteralTypeInference.ts(31,18): error TS2322: Type '({ id: number; trueness: boolean; } | { id: number; name: string; })[]' is not assignable to type '{ id: number; }[]'.
Type '{ id: number; trueness: boolean; } | { id: number; name: string; }' is not assignable to type '{ id: number; }'.
Type '{ id: number; trueness: boolean; }' is not assignable to type '{ id: number; }'.
Object literal may only specify known properties, and 'trueness' does not exist in type '{ id: number; }'.
tests/cases/compiler/arrayLiteralTypeInference.ts(14,14): error TS2322: Type '{ id: number; trueness: boolean; }' is not assignable to type 'Action'.
Object literal may only specify known properties, and 'trueness' does not exist in type 'Action'.
tests/cases/compiler/arrayLiteralTypeInference.ts(15,14): error TS2322: Type '{ id: number; name: string; }' is not assignable to type 'Action'.
Object literal may only specify known properties, and 'name' does not exist in type 'Action'.
tests/cases/compiler/arrayLiteralTypeInference.ts(31,18): error TS2322: Type '{ id: number; trueness: boolean; }' is not assignable to type '{ id: number; }'.
Object literal may only specify known properties, and 'trueness' does not exist in type '{ id: number; }'.
tests/cases/compiler/arrayLiteralTypeInference.ts(32,18): error TS2322: Type '{ id: number; name: string; }' is not assignable to type '{ id: number; }'.
Object literal may only specify known properties, and 'name' does not exist in type '{ id: number; }'.
==== tests/cases/compiler/arrayLiteralTypeInference.ts (2 errors) ====
==== tests/cases/compiler/arrayLiteralTypeInference.ts (4 errors) ====
class Action {
id: number;
}
@@ -24,11 +24,12 @@ tests/cases/compiler/arrayLiteralTypeInference.ts(31,18): error TS2322: Type '({
var x1: Action[] = [
{ id: 2, trueness: false },
~~~~~~~~~~~~~~~
!!! error TS2322: Type '({ id: number; trueness: boolean; } | { id: number; name: string; })[]' is not assignable to type 'Action[]'.
!!! error TS2322: Type '{ id: number; trueness: boolean; } | { id: number; name: string; }' is not assignable to type 'Action'.
!!! error TS2322: Type '{ id: number; trueness: boolean; }' is not assignable to type 'Action'.
!!! error TS2322: Object literal may only specify known properties, and 'trueness' does not exist in type 'Action'.
!!! error TS2322: Type '{ id: number; trueness: boolean; }' is not assignable to type 'Action'.
!!! error TS2322: Object literal may only specify known properties, and 'trueness' does not exist in type 'Action'.
{ id: 3, name: "three" }
~~~~~~~~~~~~~
!!! error TS2322: Type '{ id: number; name: string; }' is not assignable to type 'Action'.
!!! error TS2322: Object literal may only specify known properties, and 'name' does not exist in type 'Action'.
]
var x2: Action[] = [
@@ -46,11 +47,12 @@ tests/cases/compiler/arrayLiteralTypeInference.ts(31,18): error TS2322: Type '({
[
{ id: 2, trueness: false },
~~~~~~~~~~~~~~~
!!! error TS2322: Type '({ id: number; trueness: boolean; } | { id: number; name: string; })[]' is not assignable to type '{ id: number; }[]'.
!!! error TS2322: Type '{ id: number; trueness: boolean; } | { id: number; name: string; }' is not assignable to type '{ id: number; }'.
!!! error TS2322: Type '{ id: number; trueness: boolean; }' is not assignable to type '{ id: number; }'.
!!! error TS2322: Object literal may only specify known properties, and 'trueness' does not exist in type '{ id: number; }'.
!!! error TS2322: Type '{ id: number; trueness: boolean; }' is not assignable to type '{ id: number; }'.
!!! error TS2322: Object literal may only specify known properties, and 'trueness' does not exist in type '{ id: number; }'.
{ id: 3, name: "three" }
~~~~~~~~~~~~~
!!! error TS2322: Type '{ id: number; name: string; }' is not assignable to type '{ id: number; }'.
!!! error TS2322: Object literal may only specify known properties, and 'name' does not exist in type '{ id: number; }'.
]
var z2: { id: number }[] =
@@ -1,11 +1,10 @@
tests/cases/conformance/expressions/arrayLiterals/arrayLiterals.ts(24,77): error TS2322: Type '({ a: string; b: number; c: string; } | { a: string; b: number; c: number; })[]' is not assignable to type '{ [n: number]: { a: string; b: number; }; }'.
Index signatures are incompatible.
Type '{ a: string; b: number; c: string; } | { a: string; b: number; c: number; }' is not assignable to type '{ a: string; b: number; }'.
Type '{ a: string; b: number; c: string; }' is not assignable to type '{ a: string; b: number; }'.
Object literal may only specify known properties, and 'c' does not exist in type '{ a: string; b: number; }'.
tests/cases/conformance/expressions/arrayLiterals/arrayLiterals.ts(24,77): error TS2322: Type '{ a: string; b: number; c: string; }' is not assignable to type '{ a: string; b: number; }'.
Object literal may only specify known properties, and 'c' does not exist in type '{ a: string; b: number; }'.
tests/cases/conformance/expressions/arrayLiterals/arrayLiterals.ts(24,101): error TS2322: Type '{ a: string; b: number; c: number; }' is not assignable to type '{ a: string; b: number; }'.
Object literal may only specify known properties, and 'c' does not exist in type '{ a: string; b: number; }'.
==== tests/cases/conformance/expressions/arrayLiterals/arrayLiterals.ts (1 errors) ====
==== tests/cases/conformance/expressions/arrayLiterals/arrayLiterals.ts (2 errors) ====
// Empty array literal with no contextual type has type Undefined[]
var arr1= [[], [1], ['']];
@@ -31,11 +30,13 @@ tests/cases/conformance/expressions/arrayLiterals/arrayLiterals.ts(24,77): error
// Contextual type C with numeric index signature makes array literal of EveryType E of type BCT(E,C)[]
var context1: { [n: number]: { a: string; b: number; }; } = [{ a: '', b: 0, c: '' }, { a: "", b: 3, c: 0 }];
~~~~~
!!! error TS2322: Type '({ a: string; b: number; c: string; } | { a: string; b: number; c: number; })[]' is not assignable to type '{ [n: number]: { a: string; b: number; }; }'.
!!! error TS2322: Index signatures are incompatible.
!!! error TS2322: Type '{ a: string; b: number; c: string; } | { a: string; b: number; c: number; }' is not assignable to type '{ a: string; b: number; }'.
!!! error TS2322: Type '{ a: string; b: number; c: string; }' is not assignable to type '{ a: string; b: number; }'.
!!! error TS2322: Object literal may only specify known properties, and 'c' does not exist in type '{ a: string; b: number; }'.
!!! error TS2322: Type '{ a: string; b: number; c: string; }' is not assignable to type '{ a: string; b: number; }'.
!!! error TS2322: Object literal may only specify known properties, and 'c' does not exist in type '{ a: string; b: number; }'.
!!! related TS6501 tests/cases/conformance/expressions/arrayLiterals/arrayLiterals.ts:24:17: The expected type comes from this index signature.
~~~~
!!! error TS2322: Type '{ a: string; b: number; c: number; }' is not assignable to type '{ a: string; b: number; }'.
!!! error TS2322: Object literal may only specify known properties, and 'c' does not exist in type '{ a: string; b: number; }'.
!!! related TS6501 tests/cases/conformance/expressions/arrayLiterals/arrayLiterals.ts:24:17: The expected type comes from this index signature.
var context2 = [{ a: '', b: 0, c: '' }, { a: "", b: 3, c: 0 }];
// Contextual type C with numeric index signature of type Base makes array literal of Derived have type Base[]
@@ -1,12 +1,10 @@
tests/cases/compiler/arraySigChecking.ts(11,17): error TS1023: An index signature parameter type must be 'string' or 'number'.
tests/cases/compiler/arraySigChecking.ts(18,5): error TS2322: Type 'void[]' is not assignable to type 'string[]'.
Type 'void' is not assignable to type 'string'.
tests/cases/compiler/arraySigChecking.ts(22,1): error TS2322: Type 'number[][]' is not assignable to type 'number[][][]'.
Type 'number[]' is not assignable to type 'number[][]'.
Type 'number' is not assignable to type 'number[]'.
tests/cases/compiler/arraySigChecking.ts(18,27): error TS2322: Type 'void' is not assignable to type 'string'.
tests/cases/compiler/arraySigChecking.ts(22,13): error TS2322: Type 'number' is not assignable to type 'number[]'.
tests/cases/compiler/arraySigChecking.ts(22,16): error TS2322: Type 'number' is not assignable to type 'number[]'.
==== tests/cases/compiler/arraySigChecking.ts (3 errors) ====
==== tests/cases/compiler/arraySigChecking.ts (4 errors) ====
declare module M {
interface iBar { t: any; }
interface iFoo extends iBar {
@@ -27,17 +25,16 @@ tests/cases/compiler/arraySigChecking.ts(22,1): error TS2322: Type 'number[][]'
}
var myVar: myInt;
var strArray: string[] = [myVar.voidFn()];
~~~~~~~~
!!! error TS2322: Type 'void[]' is not assignable to type 'string[]'.
!!! error TS2322: Type 'void' is not assignable to type 'string'.
~~~~~~~~~~~~~~
!!! error TS2322: Type 'void' is not assignable to type 'string'.
var myArray: number[][][];
myArray = [[1, 2]];
~~~~~~~
!!! error TS2322: Type 'number[][]' is not assignable to type 'number[][][]'.
!!! error TS2322: Type 'number[]' is not assignable to type 'number[][]'.
!!! error TS2322: Type 'number' is not assignable to type 'number[]'.
~
!!! error TS2322: Type 'number' is not assignable to type 'number[]'.
~
!!! error TS2322: Type 'number' is not assignable to type 'number[]'.
function isEmpty(l: { length: number }) {
return l.length === 0;
@@ -1,7 +1,7 @@
tests/cases/compiler/assignmentCompatBug5.ts(2,8): error TS2345: Argument of type '{ b: number; }' is not assignable to parameter of type '{ a: number; }'.
Object literal may only specify known properties, and 'b' does not exist in type '{ a: number; }'.
tests/cases/compiler/assignmentCompatBug5.ts(5,6): error TS2345: Argument of type 'string[]' is not assignable to parameter of type 'number[]'.
Type 'string' is not assignable to type 'number'.
tests/cases/compiler/assignmentCompatBug5.ts(5,7): error TS2322: Type 'string' is not assignable to type 'number'.
tests/cases/compiler/assignmentCompatBug5.ts(5,12): error TS2322: Type 'string' is not assignable to type 'number'.
tests/cases/compiler/assignmentCompatBug5.ts(8,6): error TS2345: Argument of type '(s: string) => void' is not assignable to parameter of type '(n: number) => number'.
Types of parameters 's' and 'n' are incompatible.
Type 'number' is not assignable to type 'string'.
@@ -9,7 +9,7 @@ tests/cases/compiler/assignmentCompatBug5.ts(9,6): error TS2345: Argument of typ
Type 'void' is not assignable to type 'number'.
==== tests/cases/compiler/assignmentCompatBug5.ts (4 errors) ====
==== tests/cases/compiler/assignmentCompatBug5.ts (5 errors) ====
function foo1(x: { a: number; }) { }
foo1({ b: 5 });
~~~~
@@ -18,9 +18,10 @@ tests/cases/compiler/assignmentCompatBug5.ts(9,6): error TS2345: Argument of typ
function foo2(x: number[]) { }
foo2(["s", "t"]);
~~~~~~~~~~
!!! error TS2345: Argument of type 'string[]' is not assignable to parameter of type 'number[]'.
!!! error TS2345: Type 'string' is not assignable to type 'number'.
~~~
!!! error TS2322: Type 'string' is not assignable to type 'number'.
~~~
!!! error TS2322: Type 'string' is not assignable to type 'number'.
function foo3(x: (n: number) =>number) { };
foo3((s:string) => { });
@@ -10,7 +10,6 @@ tests/cases/compiler/assignmentToObjectAndFunction.ts(29,5): error TS2322: Type
var errObj: Object = { toString: 0 }; // Error, incompatible toString
~~~~~~~~
!!! error TS2322: Type 'number' is not assignable to type '() => string'.
!!! related TS6500 /.ts/lib.es5.d.ts:125:5: The expected type comes from property 'toString' which is declared here on type 'Object'
var goodObj: Object = {
toString(x?) {
return "";
@@ -1,6 +1,5 @@
tests/cases/compiler/chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.ts(19,59): error TS2345: Argument of type '(c: C) => B' is not assignable to parameter of type '(x: C) => C'.
Type 'B' is not assignable to type 'C'.
Property 'z' is missing in type 'B'.
tests/cases/compiler/chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.ts(19,64): error TS2322: Type 'B' is not assignable to type 'C'.
Property 'z' is missing in type 'B'.
==== tests/cases/compiler/chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.ts (1 errors) ====
@@ -23,7 +22,7 @@ tests/cases/compiler/chainedCallsWithTypeParameterConstrainedToOtherTypeParamete
// Ok to go down the chain, but error to try to climb back up
(new Chain(new A)).then(a => new B).then(b => new C).then(c => new B).then(b => new A);
~~~~~~~~~~
!!! error TS2345: Argument of type '(c: C) => B' is not assignable to parameter of type '(x: C) => C'.
!!! error TS2345: Type 'B' is not assignable to type 'C'.
!!! error TS2345: Property 'z' is missing in type 'B'.
~~~~~
!!! error TS2322: Type 'B' is not assignable to type 'C'.
!!! error TS2322: Property 'z' is missing in type 'B'.
!!! related TS6502 tests/cases/compiler/chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.ts:3:27: The expected type comes from the return type of this signature.
@@ -1,7 +1,5 @@
tests/cases/compiler/chainedCallsWithTypeParameterConstrainedToOtherTypeParameter2.ts(7,43): error TS2345: Argument of type '(ss: S) => T' is not assignable to parameter of type '(x: S) => S'.
Type 'T' is not assignable to type 'S'.
tests/cases/compiler/chainedCallsWithTypeParameterConstrainedToOtherTypeParameter2.ts(10,29): error TS2345: Argument of type '(ss: S) => T' is not assignable to parameter of type '(x: S) => S'.
Type 'T' is not assignable to type 'S'.
tests/cases/compiler/chainedCallsWithTypeParameterConstrainedToOtherTypeParameter2.ts(7,49): error TS2322: Type 'T' is not assignable to type 'S'.
tests/cases/compiler/chainedCallsWithTypeParameterConstrainedToOtherTypeParameter2.ts(10,35): error TS2322: Type 'T' is not assignable to type 'S'.
tests/cases/compiler/chainedCallsWithTypeParameterConstrainedToOtherTypeParameter2.ts(32,9): error TS2322: Type '""' is not assignable to type 'number'.
tests/cases/compiler/chainedCallsWithTypeParameterConstrainedToOtherTypeParameter2.ts(36,9): error TS2322: Type '""' is not assignable to type 'number'.
tests/cases/compiler/chainedCallsWithTypeParameterConstrainedToOtherTypeParameter2.ts(37,9): error TS2322: Type '""' is not assignable to type 'number'.
@@ -15,15 +13,15 @@ tests/cases/compiler/chainedCallsWithTypeParameterConstrainedToOtherTypeParamete
var s: S;
// Ok to go down the chain, but error to climb up the chain
(new Chain(t)).then(tt => s).then(ss => t);
~~~~~~~
!!! error TS2345: Argument of type '(ss: S) => T' is not assignable to parameter of type '(x: S) => S'.
!!! error TS2345: Type 'T' is not assignable to type 'S'.
~
!!! error TS2322: Type 'T' is not assignable to type 'S'.
!!! related TS6502 tests/cases/compiler/chainedCallsWithTypeParameterConstrainedToOtherTypeParameter2.ts:3:27: The expected type comes from the return type of this signature.
// But error to try to climb up the chain
(new Chain(s)).then(ss => t);
~~~~~~~
!!! error TS2345: Argument of type '(ss: S) => T' is not assignable to parameter of type '(x: S) => S'.
!!! error TS2345: Type 'T' is not assignable to type 'S'.
~
!!! error TS2322: Type 'T' is not assignable to type 'S'.
!!! related TS6502 tests/cases/compiler/chainedCallsWithTypeParameterConstrainedToOtherTypeParameter2.ts:3:27: The expected type comes from the return type of this signature.
// Staying at T or S should be fine
(new Chain(t)).then(tt => t).then(tt => t).then(tt => t);
@@ -1,11 +1,9 @@
tests/cases/compiler/contextualTyping11.ts(1,20): error TS2322: Type 'foo[]' is not assignable to type '{ id: number; }[]'.
Type 'foo' is not assignable to type '{ id: number; }'.
Property 'id' is missing in type 'foo'.
tests/cases/compiler/contextualTyping11.ts(1,42): error TS2322: Type 'foo' is not assignable to type '{ id: number; }'.
Property 'id' is missing in type 'foo'.
==== tests/cases/compiler/contextualTyping11.ts (1 errors) ====
class foo { public bar:{id:number;}[] = [<foo>({})]; }
~~~
!!! error TS2322: Type 'foo[]' is not assignable to type '{ id: number; }[]'.
!!! error TS2322: Type 'foo' is not assignable to type '{ id: number; }'.
!!! error TS2322: Property 'id' is missing in type 'foo'.
~~~~~~~~~
!!! error TS2322: Type 'foo' is not assignable to type '{ id: number; }'.
!!! error TS2322: Property 'id' is missing in type 'foo'.
@@ -1,13 +1,9 @@
tests/cases/compiler/contextualTyping12.ts(1,57): error TS2322: Type '({ id: number; } | { id: number; name: string; })[]' is not assignable to type '{ id: number; }[]'.
Type '{ id: number; } | { id: number; name: string; }' is not assignable to type '{ id: number; }'.
Type '{ id: number; name: string; }' is not assignable to type '{ id: number; }'.
Object literal may only specify known properties, and 'name' does not exist in type '{ id: number; }'.
tests/cases/compiler/contextualTyping12.ts(1,57): error TS2322: Type '{ id: number; name: string; }' is not assignable to type '{ id: number; }'.
Object literal may only specify known properties, and 'name' does not exist in type '{ id: number; }'.
==== tests/cases/compiler/contextualTyping12.ts (1 errors) ====
class foo { public bar:{id:number;}[] = [{id:1}, {id:2, name:"foo"}]; }
~~~~~~~~~~
!!! error TS2322: Type '({ id: number; } | { id: number; name: string; })[]' is not assignable to type '{ id: number; }[]'.
!!! error TS2322: Type '{ id: number; } | { id: number; name: string; }' is not assignable to type '{ id: number; }'.
!!! error TS2322: Type '{ id: number; name: string; }' is not assignable to type '{ id: number; }'.
!!! error TS2322: Object literal may only specify known properties, and 'name' does not exist in type '{ id: number; }'.
!!! error TS2322: Type '{ id: number; name: string; }' is not assignable to type '{ id: number; }'.
!!! error TS2322: Object literal may only specify known properties, and 'name' does not exist in type '{ id: number; }'.
@@ -1,13 +1,9 @@
tests/cases/compiler/contextualTyping20.ts(1,58): error TS2322: Type '({ id: number; } | { id: number; name: string; })[]' is not assignable to type '{ id: number; }[]'.
Type '{ id: number; } | { id: number; name: string; }' is not assignable to type '{ id: number; }'.
Type '{ id: number; name: string; }' is not assignable to type '{ id: number; }'.
Object literal may only specify known properties, and 'name' does not exist in type '{ id: number; }'.
tests/cases/compiler/contextualTyping20.ts(1,58): error TS2322: Type '{ id: number; name: string; }' is not assignable to type '{ id: number; }'.
Object literal may only specify known properties, and 'name' does not exist in type '{ id: number; }'.
==== tests/cases/compiler/contextualTyping20.ts (1 errors) ====
var foo:{id:number;}[] = [{id:1}]; foo = [{id:1}, {id:2, name:"foo"}];
~~~~~~~~~~
!!! error TS2322: Type '({ id: number; } | { id: number; name: string; })[]' is not assignable to type '{ id: number; }[]'.
!!! error TS2322: Type '{ id: number; } | { id: number; name: string; }' is not assignable to type '{ id: number; }'.
!!! error TS2322: Type '{ id: number; name: string; }' is not assignable to type '{ id: number; }'.
!!! error TS2322: Object literal may only specify known properties, and 'name' does not exist in type '{ id: number; }'.
!!! error TS2322: Type '{ id: number; name: string; }' is not assignable to type '{ id: number; }'.
!!! error TS2322: Object literal may only specify known properties, and 'name' does not exist in type '{ id: number; }'.
@@ -1,11 +1,7 @@
tests/cases/compiler/contextualTyping21.ts(1,36): error TS2322: Type '(number | { id: number; })[]' is not assignable to type '{ id: number; }[]'.
Type 'number | { id: number; }' is not assignable to type '{ id: number; }'.
Type 'number' is not assignable to type '{ id: number; }'.
tests/cases/compiler/contextualTyping21.ts(1,51): error TS2322: Type 'number' is not assignable to type '{ id: number; }'.
==== tests/cases/compiler/contextualTyping21.ts (1 errors) ====
var foo:{id:number;}[] = [{id:1}]; foo = [{id:1}, 1];
~~~
!!! error TS2322: Type '(number | { id: number; })[]' is not assignable to type '{ id: number; }[]'.
!!! error TS2322: Type 'number | { id: number; }' is not assignable to type '{ id: number; }'.
!!! error TS2322: Type 'number' is not assignable to type '{ id: number; }'.
~
!!! error TS2322: Type 'number' is not assignable to type '{ id: number; }'.
@@ -1,11 +1,7 @@
tests/cases/compiler/contextualTyping30.ts(1,37): error TS2345: Argument of type '(string | number)[]' is not assignable to parameter of type 'number[]'.
Type 'string | number' is not assignable to type 'number'.
Type 'string' is not assignable to type 'number'.
tests/cases/compiler/contextualTyping30.ts(1,41): error TS2322: Type 'string' is not assignable to type 'number'.
==== tests/cases/compiler/contextualTyping30.ts (1 errors) ====
function foo(param:number[]){}; foo([1, "a"]);
~~~~~~~~
!!! error TS2345: Argument of type '(string | number)[]' is not assignable to parameter of type 'number[]'.
!!! error TS2345: Type 'string | number' is not assignable to type 'number'.
!!! error TS2345: Type 'string' is not assignable to type 'number'.
~~~
!!! error TS2322: Type 'string' is not assignable to type 'number'.
@@ -1,13 +1,9 @@
tests/cases/compiler/contextualTyping33.ts(1,66): error TS2345: Argument of type '((() => number) | (() => string))[]' is not assignable to parameter of type '{ (): number; (i: number): number; }[]'.
Type '(() => number) | (() => string)' is not assignable to type '{ (): number; (i: number): number; }'.
Type '() => string' is not assignable to type '{ (): number; (i: number): number; }'.
Type 'string' is not assignable to type 'number'.
tests/cases/compiler/contextualTyping33.ts(1,90): error TS2322: Type '() => string' is not assignable to type '{ (): number; (i: number): number; }'.
Type 'string' is not assignable to type 'number'.
==== tests/cases/compiler/contextualTyping33.ts (1 errors) ====
function foo(param: {():number; (i:number):number; }[]) { }; foo([function(){return 1;}, function(){return "foo"}]);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2345: Argument of type '((() => number) | (() => string))[]' is not assignable to parameter of type '{ (): number; (i: number): number; }[]'.
!!! error TS2345: Type '(() => number) | (() => string)' is not assignable to type '{ (): number; (i: number): number; }'.
!!! error TS2345: Type '() => string' is not assignable to type '{ (): number; (i: number): number; }'.
!!! error TS2345: Type 'string' is not assignable to type 'number'.
~~~~~~~~
!!! error TS2322: Type '() => string' is not assignable to type '{ (): number; (i: number): number; }'.
!!! error TS2322: Type 'string' is not assignable to type 'number'.
@@ -1,13 +1,9 @@
tests/cases/compiler/contextualTyping9.ts(1,42): error TS2322: Type '({ id: number; } | { id: number; name: string; })[]' is not assignable to type '{ id: number; }[]'.
Type '{ id: number; } | { id: number; name: string; }' is not assignable to type '{ id: number; }'.
Type '{ id: number; name: string; }' is not assignable to type '{ id: number; }'.
Object literal may only specify known properties, and 'name' does not exist in type '{ id: number; }'.
tests/cases/compiler/contextualTyping9.ts(1,42): error TS2322: Type '{ id: number; name: string; }' is not assignable to type '{ id: number; }'.
Object literal may only specify known properties, and 'name' does not exist in type '{ id: number; }'.
==== tests/cases/compiler/contextualTyping9.ts (1 errors) ====
var foo:{id:number;}[] = [{id:1}, {id:2, name:"foo"}];
~~~~~~~~~~
!!! error TS2322: Type '({ id: number; } | { id: number; name: string; })[]' is not assignable to type '{ id: number; }[]'.
!!! error TS2322: Type '{ id: number; } | { id: number; name: string; }' is not assignable to type '{ id: number; }'.
!!! error TS2322: Type '{ id: number; name: string; }' is not assignable to type '{ id: number; }'.
!!! error TS2322: Object literal may only specify known properties, and 'name' does not exist in type '{ id: number; }'.
!!! error TS2322: Type '{ id: number; name: string; }' is not assignable to type '{ id: number; }'.
!!! error TS2322: Object literal may only specify known properties, and 'name' does not exist in type '{ id: number; }'.
@@ -1,7 +1,4 @@
tests/cases/compiler/contextualTypingOfArrayLiterals1.ts(5,5): error TS2322: Type '(number | Date)[]' is not assignable to type 'I'.
Index signatures are incompatible.
Type 'number | Date' is not assignable to type 'Date'.
Type 'number' is not assignable to type 'Date'.
tests/cases/compiler/contextualTypingOfArrayLiterals1.ts(5,26): error TS2322: Type 'number' is not assignable to type 'Date'.
==== tests/cases/compiler/contextualTypingOfArrayLiterals1.ts (1 errors) ====
@@ -10,11 +7,9 @@ tests/cases/compiler/contextualTypingOfArrayLiterals1.ts(5,5): error TS2322: Typ
}
var x3: I = [new Date(), 1];
~~
!!! error TS2322: Type '(number | Date)[]' is not assignable to type 'I'.
!!! error TS2322: Index signatures are incompatible.
!!! error TS2322: Type 'number | Date' is not assignable to type 'Date'.
!!! error TS2322: Type 'number' is not assignable to type 'Date'.
~
!!! error TS2322: Type 'number' is not assignable to type 'Date'.
!!! related TS6501 tests/cases/compiler/contextualTypingOfArrayLiterals1.ts:2:4: The expected type comes from this index signature.
var r2 = x3[1];
r2.getDate();
@@ -1,13 +1,8 @@
tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(4,20): error TS2322: Type '(v: number) => number' is not assignable to type '(x: number) => string'.
Type 'number' is not assignable to type 'string'.
tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(5,23): error TS2322: Type '(v: number) => number' is not assignable to type '(x: number) => string'.
Type 'number' is not assignable to type 'string'.
tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(6,25): error TS2322: Type '(v: number) => number' is not assignable to type '(x: number) => string'.
Type 'number' is not assignable to type 'string'.
tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(11,40): error TS2322: Type '(v: number) => number' is not assignable to type '(x: number) => string'.
Type 'number' is not assignable to type 'string'.
tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(16,23): error TS2322: Type '(arg: string) => number' is not assignable to type '(s: string) => string'.
Type 'number' is not assignable to type 'string'.
tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(4,38): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(5,41): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(6,43): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(11,51): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(16,35): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(21,22): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts(26,14): error TS2322: Type '"baz"' is not assignable to type '"foo" | "bar"'.
@@ -17,34 +12,33 @@ tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTyp
show: (x: number) => string;
}
function f({ show: showRename = v => v }: Show) {}
~~~~~~~~~~
!!! error TS2322: Type '(v: number) => number' is not assignable to type '(x: number) => string'.
!!! error TS2322: Type 'number' is not assignable to type 'string'.
~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
!!! related TS6502 tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts:2:11: The expected type comes from the return type of this signature.
function f2({ "show": showRename = v => v }: Show) {}
~~~~~~~~~~
!!! error TS2322: Type '(v: number) => number' is not assignable to type '(x: number) => string'.
!!! error TS2322: Type 'number' is not assignable to type 'string'.
~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
!!! related TS6502 tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts:2:11: The expected type comes from the return type of this signature.
function f3({ ["show"]: showRename = v => v }: Show) {}
~~~~~~~~~~
!!! error TS2322: Type '(v: number) => number' is not assignable to type '(x: number) => string'.
!!! error TS2322: Type 'number' is not assignable to type 'string'.
~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
!!! related TS6502 tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts:2:11: The expected type comes from the return type of this signature.
interface Nested {
nested: Show
}
function ff({ nested: nestedRename = { show: v => v } }: Nested) {}
~~~~
!!! error TS2322: Type '(v: number) => number' is not assignable to type '(x: number) => string'.
!!! error TS2322: Type 'number' is not assignable to type 'string'.
!!! related TS6500 tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts:2:5: The expected type comes from property 'show' which is declared here on type 'Show'
~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
!!! related TS6502 tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts:2:11: The expected type comes from the return type of this signature.
interface StringIdentity {
stringIdentity(s: string): string;
}
let { stringIdentity: id = arg => arg.length }: StringIdentity = { stringIdentity: x => x};
~~
!!! error TS2322: Type '(arg: string) => number' is not assignable to type '(s: string) => string'.
!!! error TS2322: Type 'number' is not assignable to type 'string'.
~~~~~~~~~~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
!!! related TS6502 tests/cases/conformance/types/contextualTypes/methodDeclarations/contextuallyTypedBindingInitializerNegative.ts:14:5: The expected type comes from the return type of this signature.
interface Tuples {
prop: [string, number];
@@ -67,7 +67,33 @@ function f6() {
y; // string | undefined
}
}
function f7(x: {}) {
if (x) {
x; // {}
}
else {
x; // {}
}
}
function f8<T>(x: T) {
if (x) {
x; // {}
}
else {
x; // {}
}
}
function f9<T extends object>(x: T) {
if (x) {
x; // {}
}
else {
x; // never
}
}
//// [controlFlowTruthiness.js]
function f1() {
@@ -131,3 +157,27 @@ function f6() {
y; // string | undefined
}
}
function f7(x) {
if (x) {
x; // {}
}
else {
x; // {}
}
}
function f8(x) {
if (x) {
x; // {}
}
else {
x; // {}
}
}
function f9(x) {
if (x) {
x; // {}
}
else {
x; // never
}
}
@@ -140,3 +140,54 @@ function f6() {
}
}
function f7(x: {}) {
>f7 : Symbol(f7, Decl(controlFlowTruthiness.ts, 67, 1))
>x : Symbol(x, Decl(controlFlowTruthiness.ts, 69, 12))
if (x) {
>x : Symbol(x, Decl(controlFlowTruthiness.ts, 69, 12))
x; // {}
>x : Symbol(x, Decl(controlFlowTruthiness.ts, 69, 12))
}
else {
x; // {}
>x : Symbol(x, Decl(controlFlowTruthiness.ts, 69, 12))
}
}
function f8<T>(x: T) {
>f8 : Symbol(f8, Decl(controlFlowTruthiness.ts, 76, 1))
>T : Symbol(T, Decl(controlFlowTruthiness.ts, 78, 12))
>x : Symbol(x, Decl(controlFlowTruthiness.ts, 78, 15))
>T : Symbol(T, Decl(controlFlowTruthiness.ts, 78, 12))
if (x) {
>x : Symbol(x, Decl(controlFlowTruthiness.ts, 78, 15))
x; // {}
>x : Symbol(x, Decl(controlFlowTruthiness.ts, 78, 15))
}
else {
x; // {}
>x : Symbol(x, Decl(controlFlowTruthiness.ts, 78, 15))
}
}
function f9<T extends object>(x: T) {
>f9 : Symbol(f9, Decl(controlFlowTruthiness.ts, 85, 1))
>T : Symbol(T, Decl(controlFlowTruthiness.ts, 87, 12))
>x : Symbol(x, Decl(controlFlowTruthiness.ts, 87, 30))
>T : Symbol(T, Decl(controlFlowTruthiness.ts, 87, 12))
if (x) {
>x : Symbol(x, Decl(controlFlowTruthiness.ts, 87, 30))
x; // {}
>x : Symbol(x, Decl(controlFlowTruthiness.ts, 87, 30))
}
else {
x; // never
>x : Symbol(x, Decl(controlFlowTruthiness.ts, 87, 30))
}
}
@@ -157,3 +157,50 @@ function f6() {
}
}
function f7(x: {}) {
>f7 : (x: {}) => void
>x : {}
if (x) {
>x : {}
x; // {}
>x : {}
}
else {
x; // {}
>x : {}
}
}
function f8<T>(x: T) {
>f8 : <T>(x: T) => void
>x : T
if (x) {
>x : T
x; // {}
>x : T
}
else {
x; // {}
>x : T
}
}
function f9<T extends object>(x: T) {
>f9 : <T extends object>(x: T) => void
>x : T
if (x) {
>x : T
x; // {}
>x : T
}
else {
x; // never
>x : never
}
}
@@ -6,6 +6,6 @@ function /*[#|*/f/*|]*/(): Promise<void> {
// ==ASYNC FUNCTION::Convert to async function==
async function f(): Promise<void> {
await fetch('https://typescriptlang.org');
const _ = await fetch('https://typescriptlang.org');
console.log("done");
}
@@ -0,0 +1,12 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/(): Promise<void> {
return fetch('https://typescriptlang.org').then( () => console.log("almost done") ).then( () => console.log("done") );
}
// ==ASYNC FUNCTION::Convert to async function==
async function f(): Promise<void> {
await fetch('https://typescriptlang.org');
console.log("almost done");
return console.log("done");
}
@@ -0,0 +1,17 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/() {
return fetch('https://typescriptlang.org').then(res);
}
function res(){
console.log("done");
}
// ==ASYNC FUNCTION::Convert to async function==
async function f() {
const result = await fetch('https://typescriptlang.org');
return res(result);
}
function res(){
console.log("done");
}
@@ -0,0 +1,17 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/() {
return fetch('https://typescriptlang.org').then(res);
}
function res(){
console.log("done");
}
// ==ASYNC FUNCTION::Convert to async function==
async function f() {
const result = await fetch('https://typescriptlang.org');
return res(result);
}
function res(){
console.log("done");
}
@@ -0,0 +1,15 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/() {
return fetch('https://typescriptlang.org').then(x => x.statusText).catch(undefined);
}
// ==ASYNC FUNCTION::Convert to async function==
async function f() {
try {
const x = await fetch('https://typescriptlang.org');
return x.statusText;
}
catch (e) { }
}
@@ -0,0 +1,15 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/() {
return fetch('https://typescriptlang.org').then(x => x.statusText).catch(undefined);
}
// ==ASYNC FUNCTION::Convert to async function==
async function f() {
try {
const x = await fetch('https://typescriptlang.org');
return x.statusText;
}
catch (e) { }
}
@@ -1,7 +1,7 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/() {
var var1:Promise<Response>, var2;
var var1: Response, var2;
return fetch('https://typescriptlang.org').then( _ =>
Promise.resolve().then( res => {
var2 = "test";
@@ -18,11 +18,11 @@ function /*[#|*/f/*|]*/() {
// ==ASYNC FUNCTION::Convert to async function==
async function f() {
var var1:Promise<Response>, var2;
await fetch('https://typescriptlang.org');
var var1: Response, var2;
const _ = await fetch('https://typescriptlang.org');
const res = await Promise.resolve();
var2 = "test";
const res_1 = fetch("https://microsoft.com");
const res_1 = await fetch("https://microsoft.com");
const response = var1 === res_1;
return res(response);
}
@@ -0,0 +1,14 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/() {
return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText).then(st => st.length)).then(x => console.log(x + 5));
}
// ==ASYNC FUNCTION::Convert to async function==
async function f() {
const s = await fetch('https://typescriptlang.org');
const st = await Promise.resolve(s.statusText);
const x = st.length;
return console.log(x + 5);
}
@@ -0,0 +1,14 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/() {
return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText).then(st => st.length)).then(x => console.log(x + 5));
}
// ==ASYNC FUNCTION::Convert to async function==
async function f() {
const s = await fetch('https://typescriptlang.org');
const st = await Promise.resolve(s.statusText);
const x = st.length;
return console.log(x + 5);
}
@@ -0,0 +1,13 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/() {
return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText.length)).then(x => console.log(x + 5));
}
// ==ASYNC FUNCTION::Convert to async function==
async function f() {
const s = await fetch('https://typescriptlang.org');
const x = await Promise.resolve(s.statusText.length);
return console.log(x + 5);
}
@@ -0,0 +1,13 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/() {
return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText.length)).then(x => console.log(x + 5));
}
// ==ASYNC FUNCTION::Convert to async function==
async function f() {
const s = await fetch('https://typescriptlang.org');
const x = await Promise.resolve(s.statusText.length);
return console.log(x + 5);
}
@@ -0,0 +1,13 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/() {
return fetch('https://typescriptlang.org').then(s => { return Promise.resolve(s.statusText.length) }).then(x => x + 5);
}
// ==ASYNC FUNCTION::Convert to async function==
async function f() {
const s = await fetch('https://typescriptlang.org');
const x = await Promise.resolve(s.statusText.length);
return x + 5;
}
@@ -0,0 +1,13 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/() {
return fetch('https://typescriptlang.org').then(s => { return Promise.resolve(s.statusText.length) }).then(x => x + 5);
}
// ==ASYNC FUNCTION::Convert to async function==
async function f() {
const s = await fetch('https://typescriptlang.org');
const x = await Promise.resolve(s.statusText.length);
return x + 5;
}
@@ -0,0 +1,12 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/() {
return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText.length));
}
// ==ASYNC FUNCTION::Convert to async function==
async function f() {
const s = await fetch('https://typescriptlang.org');
return Promise.resolve(s.statusText.length);
}
@@ -0,0 +1,12 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/() {
return fetch('https://typescriptlang.org').then(s => Promise.resolve(s.statusText.length));
}
// ==ASYNC FUNCTION::Convert to async function==
async function f() {
const s = await fetch('https://typescriptlang.org');
return Promise.resolve(s.statusText.length);
}
@@ -0,0 +1,13 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/() {
return fetch('https://typescriptlang.org').then(x => Promise.resolve(3).then(y => Promise.resolve(x.statusText.length + y)));
}
// ==ASYNC FUNCTION::Convert to async function==
async function f() {
const x = await fetch('https://typescriptlang.org');
const y = await Promise.resolve(3);
return Promise.resolve(x.statusText.length + y);
}
@@ -0,0 +1,13 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/() {
return fetch('https://typescriptlang.org').then(x => Promise.resolve(3).then(y => Promise.resolve(x.statusText.length + y)));
}
// ==ASYNC FUNCTION::Convert to async function==
async function f() {
const x = await fetch('https://typescriptlang.org');
const y = await Promise.resolve(3);
return Promise.resolve(x.statusText.length + y);
}
@@ -0,0 +1,19 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/() {
return fetch('https://typescriptlang.org').then(res).then(_ => console.log("done"));
}
function res(result) {
return Promise.resolve().then(x => console.log(result));
}
// ==ASYNC FUNCTION::Convert to async function==
async function f() {
const result = await fetch('https://typescriptlang.org');
const _ = await res(result);
return console.log("done");
}
function res(result) {
return Promise.resolve().then(x => console.log(result));
}
@@ -0,0 +1,19 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/() {
return fetch('https://typescriptlang.org').then(res).then(_ => console.log("done"));
}
function res(result) {
return Promise.resolve().then(x => console.log(result));
}
// ==ASYNC FUNCTION::Convert to async function==
async function f() {
const result = await fetch('https://typescriptlang.org');
const _ = await res(result);
return console.log("done");
}
function res(result) {
return Promise.resolve().then(x => console.log(result));
}
@@ -0,0 +1,17 @@
//// [test.ts]
interface Foo {
x: number;
}
export default Foo;
//// [test.js]
"use strict";
exports.__esModule = true;
//// [test.d.ts]
interface Foo {
x: number;
}
export default Foo;
@@ -0,0 +1,10 @@
=== /foo/test.ts ===
interface Foo {
>Foo : Symbol(Foo, Decl(test.ts, 0, 0))
x: number;
>x : Symbol(Foo.x, Decl(test.ts, 0, 15))
}
export default Foo;
>Foo : Symbol(Foo, Decl(test.ts, 0, 0))
@@ -0,0 +1,8 @@
=== /foo/test.ts ===
interface Foo {
x: number;
>x : number
}
export default Foo;
>Foo : Foo
@@ -0,0 +1,17 @@
//// [test.ts]
interface Foo {
x: number;
}
export default Foo;
//// [test.js]
"use strict";
exports.__esModule = true;
//// [test.d.ts]
interface Foo {
x: number;
}
export default Foo;
@@ -0,0 +1,10 @@
=== /foo/test.ts ===
interface Foo {
>Foo : Symbol(Foo, Decl(test.ts, 0, 0))
x: number;
>x : Symbol(Foo.x, Decl(test.ts, 0, 15))
}
export default Foo;
>Foo : Symbol(Foo, Decl(test.ts, 0, 0))
@@ -0,0 +1,8 @@
=== /foo/test.ts ===
interface Foo {
x: number;
>x : number
}
export default Foo;
>Foo : Foo
@@ -0,0 +1,16 @@
/foo/tsconfig.json(2,26): error TS5052: Option 'declarationDir' cannot be specified without specifying option 'declaration'.
==== /foo/tsconfig.json (1 errors) ====
{
"compilerOptions": { "declarationDir": "out" }
~~~~~~~~~~~~~~~~
!!! error TS5052: Option 'declarationDir' cannot be specified without specifying option 'declaration'.
}
==== /foo/test.ts (0 errors) ====
interface Foo {
x: number;
}
export default Foo;
@@ -0,0 +1,10 @@
//// [test.ts]
interface Foo {
x: number;
}
export default Foo;
//// [test.js]
"use strict";
exports.__esModule = true;
@@ -0,0 +1,10 @@
=== /foo/test.ts ===
interface Foo {
>Foo : Symbol(Foo, Decl(test.ts, 0, 0))
x: number;
>x : Symbol(Foo.x, Decl(test.ts, 0, 15))
}
export default Foo;
>Foo : Symbol(Foo, Decl(test.ts, 0, 0))

Some files were not shown because too many files have changed in this diff Show More