Merge branch 'master' into es2019

This commit is contained in:
Kagami Sascha Rosylight 2019-01-16 10:54:46 +09:00 committed by GitHub
commit d8ac9ba414
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
245 changed files with 16503 additions and 13069 deletions

View file

@ -0,0 +1,5 @@
/// <reference path='fourslash.ts'/>
////namespace wwer./**/w
verify.completions({ marker: "", exact: [], isNewIdentifierLocation: true });

View file

@ -12,7 +12,7 @@ function baselineAccept(subfolder = "") {
}
function baselineCopy(subfolder = "") {
return gulp.src([`${localBaseline}${subfolder ? `${subfolder}/` : ``}**`, `!${localBaseline}${subfolder}/**/*.delete`], { base: localBaseline, read: false })
return gulp.src([`${localBaseline}${subfolder ? `${subfolder}/` : ``}**`, `!${localBaseline}${subfolder}/**/*.delete`], { base: localBaseline })
.pipe(gulp.dest(refBaseline));
}
@ -21,4 +21,4 @@ function baselineDelete(subfolder = "") {
.pipe(rm())
.pipe(rename({ extname: "" }))
.pipe(rm(refBaseline));
}
}

View file

@ -12,6 +12,7 @@
"module": "commonjs",
"outDir": "../../built/local/tslint",
"baseUrl": "../..",
"types": ["node"],
"paths": {
"typescript": ["lib/typescript.d.ts"]
}

View file

@ -753,7 +753,7 @@ namespace ts {
function isNarrowableReference(expr: Expression): boolean {
return expr.kind === SyntaxKind.Identifier || expr.kind === SyntaxKind.ThisKeyword || expr.kind === SyntaxKind.SuperKeyword ||
isPropertyAccessExpression(expr) && isNarrowableReference(expr.expression) ||
(isPropertyAccessExpression(expr) || isNonNullExpression(expr) || isParenthesizedExpression(expr)) && isNarrowableReference(expr.expression) ||
isElementAccessExpression(expr) && expr.argumentExpression &&
(isStringLiteral(expr.argumentExpression) || isNumericLiteral(expr.argumentExpression)) &&
isNarrowableReference(expr.expression);

View file

@ -64,7 +64,9 @@ namespace ts {
const state = BuilderState.create(newProgram, getCanonicalFileName, oldState) as BuilderProgramState;
state.program = newProgram;
const compilerOptions = newProgram.getCompilerOptions();
if (!compilerOptions.outFile && !compilerOptions.out) {
// With --out or --outFile, any change affects all semantic diagnostics so no need to cache them
// With --isolatedModules, emitting changed file doesnt emit dependent files so we cant know of dependent files to retrieve errors so dont cache the errors
if (!compilerOptions.outFile && !compilerOptions.out && !compilerOptions.isolatedModules) {
state.semanticDiagnosticsPerFile = createMap<ReadonlyArray<Diagnostic>>();
}
state.changedFilesSet = createMap<true>();
@ -76,7 +78,8 @@ namespace ts {
if (useOldState) {
// Verify the sanity of old state
if (!oldState!.currentChangedFilePath) {
Debug.assert(!oldState!.affectedFiles && (!oldState!.currentAffectedFilesSignatures || !oldState!.currentAffectedFilesSignatures!.size), "Cannot reuse if only few affected files of currentChangedFile were iterated");
const affectedSignatures = oldState!.currentAffectedFilesSignatures;
Debug.assert(!oldState!.affectedFiles && (!affectedSignatures || !affectedSignatures.size), "Cannot reuse if only few affected files of currentChangedFile were iterated");
}
if (canCopySemanticDiagnostics) {
Debug.assert(!forEachKey(oldState!.changedFilesSet, path => oldState!.semanticDiagnosticsPerFile!.has(path)), "Semantic diagnostics shouldnt be available for changed files");
@ -281,10 +284,19 @@ namespace ts {
}
// If exported from path is not from cache and exported modules has path, all files referencing file exported from are affected
return !!forEachEntry(state.exportedModulesMap!, (exportedModules, exportedFromPath) =>
if (forEachEntry(state.exportedModulesMap!, (exportedModules, exportedFromPath) =>
!state.currentAffectedFilesExportedModulesMap!.has(exportedFromPath) && // If we already iterated this through cache, ignore it
exportedModules.has(filePath) &&
removeSemanticDiagnosticsOfFileAndExportsOfFile(state, exportedFromPath as Path, seenFileAndExportsOfFile)
)) {
return true;
}
// Remove diagnostics of files that import this file (without going to exports of referencing files)
return !!forEachEntry(state.referencedMap!, (referencesInFile, referencingFilePath) =>
referencesInFile.has(filePath) &&
!seenFileAndExportsOfFile.has(referencingFilePath) && // Not already removed diagnostic file
removeSemanticDiagnosticsOf(state, referencingFilePath as Path) // Dont add to seen since this is not yet done with the export removal
);
}
@ -329,15 +341,19 @@ namespace ts {
*/
function getSemanticDiagnosticsOfFile(state: BuilderProgramState, sourceFile: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic> {
const path = sourceFile.path;
const cachedDiagnostics = state.semanticDiagnosticsPerFile!.get(path);
// Report the semantic diagnostics from the cache if we already have those diagnostics present
if (cachedDiagnostics) {
return cachedDiagnostics;
if (state.semanticDiagnosticsPerFile) {
const cachedDiagnostics = state.semanticDiagnosticsPerFile.get(path);
// Report the semantic diagnostics from the cache if we already have those diagnostics present
if (cachedDiagnostics) {
return cachedDiagnostics;
}
}
// Diagnostics werent cached, get them from program, and cache the result
const diagnostics = state.program.getSemanticDiagnostics(sourceFile, cancellationToken);
state.semanticDiagnosticsPerFile!.set(path, diagnostics);
if (state.semanticDiagnosticsPerFile) {
state.semanticDiagnosticsPerFile.set(path, diagnostics);
}
return diagnostics;
}

View file

@ -444,10 +444,10 @@ namespace ts {
const circularConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
const resolvingDefaultType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
const markerSuperType = <TypeParameter>createType(TypeFlags.TypeParameter);
const markerSubType = <TypeParameter>createType(TypeFlags.TypeParameter);
const markerSuperType = createTypeParameter();
const markerSubType = createTypeParameter();
markerSubType.constraint = markerSuperType;
const markerOtherType = <TypeParameter>createType(TypeFlags.TypeParameter);
const markerOtherType = createTypeParameter();
const noTypePredicate = createIdentifierTypePredicate("<<unresolved>>", 0, anyType);
@ -663,7 +663,6 @@ namespace ts {
const subtypeRelation = createMap<RelationComparisonResult>();
const assignableRelation = createMap<RelationComparisonResult>();
const definitelyAssignableRelation = createMap<RelationComparisonResult>();
const comparableRelation = createMap<RelationComparisonResult>();
const identityRelation = createMap<RelationComparisonResult>();
const enumRelation = createMap<RelationComparisonResult>();
@ -2408,11 +2407,18 @@ namespace ts {
// combine other declarations with the module or variable (e.g. a class/module, function/module, interface/variable).
function resolveESModuleSymbol(moduleSymbol: Symbol | undefined, referencingLocation: Node, dontResolveAlias: boolean): Symbol | undefined {
const symbol = resolveExternalModuleSymbol(moduleSymbol, dontResolveAlias);
if (!dontResolveAlias && symbol) {
if (!(symbol.flags & (SymbolFlags.Module | SymbolFlags.Variable)) && !getDeclarationOfKind(symbol, SyntaxKind.SourceFile)) {
error(referencingLocation, Diagnostics.Module_0_resolves_to_a_non_module_entity_and_cannot_be_imported_using_this_construct, symbolToString(moduleSymbol!));
const compilerOptionName = moduleKind >= ModuleKind.ES2015
? "allowSyntheticDefaultImports"
: "esModuleInterop";
error(referencingLocation, Diagnostics.This_module_can_only_be_referenced_with_ECMAScript_imports_Slashexports_by_turning_on_the_0_flag_and_referencing_its_default_export, compilerOptionName);
return symbol;
}
if (compilerOptions.esModuleInterop) {
const referenceParent = referencingLocation.parent;
if (
@ -2745,6 +2751,12 @@ namespace ts {
return getUnionType(arrayFrom(typeofEQFacts.keys(), getLiteralType));
}
function createTypeParameter(symbol?: Symbol) {
const type = <TypeParameter>createType(TypeFlags.TypeParameter);
if (symbol) type.symbol = symbol;
return type;
}
// A reserved member name starts with two underscores, but the third character cannot be an underscore
// or the @ symbol. A third underscore indicates an escaped form of an identifer that started
// with at least two underscores. The @ character indicates that the name is denoted by a well known ES
@ -4919,7 +4931,7 @@ namespace ts {
if (strictNullChecks && declaration.initializer && !(getFalsyFlags(checkDeclarationInitializer(declaration)) & TypeFlags.Undefined)) {
type = getTypeWithFacts(type, TypeFacts.NEUndefined);
}
return declaration.initializer && !getContextualTypeForVariableLikeDeclaration(walkUpBindingElementsAndPatterns(declaration)) ?
return declaration.initializer && !getEffectiveTypeAnnotationNode(walkUpBindingElementsAndPatterns(declaration)) ?
getUnionType([type, checkDeclarationInitializer(declaration)], UnionReduction.Subtype) :
type;
}
@ -5419,6 +5431,10 @@ namespace ts {
// Handle variable, parameter or property
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
// Symbol is property of some kind that is merged with something - should use `getTypeOfFuncClassEnumModule` and not `getTypeOfVariableOrParameterOrProperty`
if (symbol.flags & SymbolFlags.ValueModule) {
return getTypeOfFuncClassEnumModule(symbol);
}
return errorType;
}
let type: Type | undefined;
@ -5474,6 +5490,10 @@ namespace ts {
}
if (!popTypeResolution()) {
// Symbol is property of some kind that is merged with something - should use `getTypeOfFuncClassEnumModule` and not `getTypeOfVariableOrParameterOrProperty`
if (symbol.flags & SymbolFlags.ValueModule) {
return getTypeOfFuncClassEnumModule(symbol);
}
type = reportCircularityError(symbol);
}
return type;
@ -6085,9 +6105,8 @@ namespace ts {
(<GenericType>type).instantiations.set(getTypeListId(type.typeParameters), <GenericType>type);
(<GenericType>type).target = <GenericType>type;
(<GenericType>type).typeArguments = type.typeParameters;
type.thisType = <TypeParameter>createType(TypeFlags.TypeParameter);
type.thisType = createTypeParameter(symbol);
type.thisType.isThisType = true;
type.thisType.symbol = symbol;
type.thisType.constraint = type;
}
}
@ -6228,20 +6247,12 @@ namespace ts {
function getDeclaredTypeOfTypeParameter(symbol: Symbol): TypeParameter {
const links = getSymbolLinks(symbol);
if (!links.declaredType) {
const type = <TypeParameter>createType(TypeFlags.TypeParameter);
type.symbol = symbol;
links.declaredType = type;
}
return <TypeParameter>links.declaredType;
return links.declaredType || (links.declaredType = createTypeParameter(symbol));
}
function getDeclaredTypeOfAlias(symbol: Symbol): Type {
const links = getSymbolLinks(symbol);
if (!links.declaredType) {
links.declaredType = getDeclaredTypeOfSymbol(resolveAlias(symbol));
}
return links.declaredType;
return links.declaredType || (links.declaredType = getDeclaredTypeOfSymbol(resolveAlias(symbol)));
}
function getDeclaredTypeOfSymbol(symbol: Symbol): Type {
@ -6930,7 +6941,7 @@ namespace ts {
function resolveUnionTypeMembers(type: UnionType) {
// The members and properties collections are empty for union types. To get all properties of a union
// type use getPropertiesOfType (only the language service uses this).
const callSignatures = getUnionSignatures(map(type.types, t => getSignaturesOfType(t, SignatureKind.Call)));
const callSignatures = getUnionSignatures(map(type.types, t => t === globalFunctionType ? [unknownSignature] : getSignaturesOfType(t, SignatureKind.Call)));
const constructSignatures = getUnionSignatures(map(type.types, t => getSignaturesOfType(t, SignatureKind.Construct)));
const stringIndexInfo = getUnionIndexInfo(type.types, IndexKind.String);
const numberIndexInfo = getUnionIndexInfo(type.types, IndexKind.Number);
@ -7084,6 +7095,39 @@ namespace ts {
setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, undefined);
}
// Return the lower bound of the key type in a mapped type. Intuitively, the lower
// bound includes those keys that are known to always be present, for example because
// because of constraints on type parameters (e.g. 'keyof T' for a constrained T).
function getLowerBoundOfKeyType(type: Type): Type {
if (type.flags & (TypeFlags.Any | TypeFlags.Primitive)) {
return type;
}
if (type.flags & TypeFlags.Index) {
return getIndexType(getApparentType((<IndexType>type).type));
}
if (type.flags & TypeFlags.Conditional) {
return getLowerBoundOfConditionalType(<ConditionalType>type);
}
if (type.flags & TypeFlags.Union) {
return getUnionType(sameMap((<UnionType>type).types, getLowerBoundOfKeyType));
}
if (type.flags & TypeFlags.Intersection) {
return getIntersectionType(sameMap((<UnionType>type).types, getLowerBoundOfKeyType));
}
return neverType;
}
function getLowerBoundOfConditionalType(type: ConditionalType) {
if (type.root.isDistributive) {
const constraint = getLowerBoundOfKeyType(type.checkType);
if (constraint !== type.checkType) {
const mapper = makeUnaryTypeMapper(type.root.checkType, constraint);
return getConditionalTypeInstantiation(type, combineTypeMappers(mapper, type.mapper));
}
}
return type;
}
/** Resolve the members of a mapped type { [P in K]: T } */
function resolveMappedTypeMembers(type: MappedType) {
const members: SymbolTable = createSymbolTable();
@ -7112,10 +7156,7 @@ namespace ts {
}
}
else {
// If the key type is a 'keyof X', obtain 'keyof C' where C is the base constraint of X.
// Then iterate over the constituents of the key type.
const iterationType = constraintType.flags & TypeFlags.Index ? getIndexType(getApparentType((<IndexType>constraintType).type)) : constraintType;
forEachType(iterationType, addMemberForKeyType);
forEachType(getLowerBoundOfKeyType(constraintType), addMemberForKeyType);
}
setStructuredTypeMembers(type, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
@ -7383,7 +7424,7 @@ namespace ts {
if (type.root.isDistributive) {
const simplified = getSimplifiedType(type.checkType);
const constraint = simplified === type.checkType ? getConstraintOfType(simplified) : simplified;
if (constraint) {
if (constraint && constraint !== type.checkType) {
const mapper = makeUnaryTypeMapper(type.root.checkType, constraint);
const instantiated = getConditionalTypeInstantiation(type, combineTypeMappers(mapper, type.mapper));
if (!(instantiated.flags & TypeFlags.Never)) {
@ -7669,38 +7710,37 @@ namespace ts {
return props[0];
}
let declarations: Declaration[] | undefined;
let commonType: Type | undefined;
let firstType: Type | undefined;
let nameType: Type | undefined;
const propTypes: Type[] = [];
let first = true;
let commonValueDeclaration: Declaration | undefined;
let firstValueDeclaration: Declaration | undefined;
let hasNonUniformValueDeclaration = false;
for (const prop of props) {
if (!commonValueDeclaration) {
commonValueDeclaration = prop.valueDeclaration;
if (!firstValueDeclaration) {
firstValueDeclaration = prop.valueDeclaration;
}
else if (prop.valueDeclaration !== commonValueDeclaration) {
else if (prop.valueDeclaration !== firstValueDeclaration) {
hasNonUniformValueDeclaration = true;
}
declarations = addRange(declarations, prop.declarations);
const type = getTypeOfSymbol(prop);
if (first) {
commonType = type;
if (!firstType) {
firstType = type;
nameType = prop.nameType;
first = false;
}
else {
if (type !== commonType) {
checkFlags |= CheckFlags.HasNonUniformType;
}
else if (type !== firstType) {
checkFlags |= CheckFlags.HasNonUniformType;
}
if (isLiteralType(type)) {
checkFlags |= CheckFlags.HasLiteralType;
}
propTypes.push(type);
}
addRange(propTypes, indexTypes);
const result = createSymbol(SymbolFlags.Property | commonFlags, name, syntheticFlag | checkFlags);
result.containingType = containingType;
if (!hasNonUniformValueDeclaration && commonValueDeclaration) {
result.valueDeclaration = commonValueDeclaration;
if (!hasNonUniformValueDeclaration && firstValueDeclaration) {
result.valueDeclaration = firstValueDeclaration;
}
result.declarations = declarations!;
result.nameType = nameType;
@ -7928,22 +7968,17 @@ namespace ts {
const numTypeArguments = length(typeArguments);
if (isJavaScriptImplicitAny || (numTypeArguments >= minTypeArgumentCount && numTypeArguments <= numTypeParameters)) {
const result = typeArguments ? typeArguments.slice() : [];
// Map an unsatisfied type parameter with a default type.
// If a type parameter does not have a default type, or if the default type
// is a forward reference, the empty object type is used.
const baseDefaultType = getDefaultTypeArgumentType(isJavaScriptImplicitAny);
const circularityMapper = createTypeMapper(typeParameters!, map(typeParameters!, () => baseDefaultType));
// Map invalid forward references in default types to the error type
for (let i = numTypeArguments; i < numTypeParameters; i++) {
result[i] = instantiateType(getConstraintFromTypeParameter(typeParameters![i]) || baseDefaultType, circularityMapper);
result[i] = errorType;
}
const baseDefaultType = getDefaultTypeArgumentType(isJavaScriptImplicitAny);
for (let i = numTypeArguments; i < numTypeParameters; i++) {
const mapper = createTypeMapper(typeParameters!, result);
let defaultType = getDefaultFromTypeParameter(typeParameters![i]);
if (isJavaScriptImplicitAny && defaultType && isTypeIdenticalTo(defaultType, emptyObjectType)) {
defaultType = anyType;
}
result[i] = defaultType ? instantiateType(defaultType, mapper) : baseDefaultType;
result[i] = defaultType ? instantiateType(defaultType, createTypeMapper(typeParameters!, result)) : baseDefaultType;
}
result.length = typeParameters!.length;
return result;
@ -9025,7 +9060,7 @@ namespace ts {
if (arity) {
typeParameters = new Array(arity);
for (let i = 0; i < arity; i++) {
const typeParameter = typeParameters[i] = <TypeParameter>createType(TypeFlags.TypeParameter);
const typeParameter = typeParameters[i] = createTypeParameter();
if (i < maxLength) {
const property = createSymbol(SymbolFlags.Property | (i >= minLength ? SymbolFlags.Optional : 0), "" + i as __String);
property.type = typeParameter;
@ -9046,7 +9081,7 @@ namespace ts {
type.instantiations.set(getTypeListId(type.typeParameters), <GenericType>type);
type.target = <GenericType>type;
type.typeArguments = type.typeParameters;
type.thisType = <TypeParameter>createType(TypeFlags.TypeParameter);
type.thisType = createTypeParameter();
type.thisType.isThisType = true;
type.thisType.constraint = type;
type.declaredProperties = properties;
@ -9947,7 +9982,7 @@ namespace ts {
if (checkType === wildcardType || extendsType === wildcardType) {
return wildcardType;
}
const checkTypeInstantiable = maybeTypeOfKind(checkType, TypeFlags.Instantiable);
const checkTypeInstantiable = maybeTypeOfKind(checkType, TypeFlags.Instantiable | TypeFlags.GenericMappedType);
let combinedMapper: TypeMapper | undefined;
if (root.inferTypeParameters) {
const context = createInferenceContext(root.inferTypeParameters, /*signature*/ undefined, InferenceFlags.None);
@ -9962,7 +9997,7 @@ namespace ts {
// Instantiate the extends type including inferences for 'infer T' type parameters
const inferredExtendsType = combinedMapper ? instantiateType(root.extendsType, combinedMapper) : extendsType;
// We attempt to resolve the conditional type only when the check and extends types are non-generic
if (!checkTypeInstantiable && !maybeTypeOfKind(inferredExtendsType, TypeFlags.Instantiable)) {
if (!checkTypeInstantiable && !maybeTypeOfKind(inferredExtendsType, TypeFlags.Instantiable | TypeFlags.GenericMappedType)) {
if (inferredExtendsType.flags & TypeFlags.AnyOrUnknown) {
return instantiateType(root.trueType, mapper);
}
@ -9974,14 +10009,15 @@ namespace ts {
// types with type parameters mapped to the wildcard type, the most permissive instantiations
// possible (the wildcard type is assignable to and from all types). If those are not related,
// then no instatiations will be and we can just return the false branch type.
if (!isTypeAssignableTo(getWildcardInstantiation(checkType), getWildcardInstantiation(inferredExtendsType))) {
if (!isTypeAssignableTo(getPermissiveInstantiation(checkType), getPermissiveInstantiation(inferredExtendsType))) {
return instantiateType(root.falseType, mapper);
}
// Return trueType for a definitely true extends check. The definitely assignable relation excludes
// type variable constraints from consideration. Without the definitely assignable relation, the type
// Return trueType for a definitely true extends check. We check instantiations of the two
// types with type parameters mapped to their restrictive form, i.e. a form of the type parameter
// that has no constraint. This ensures that, for example, the type
// type Foo<T extends { x: any }> = T extends { x: string } ? string : number
// would immediately resolve to 'string' instead of being deferred.
if (checkTypeRelatedTo(checkType, inferredExtendsType, definitelyAssignableRelation, /*errorNode*/ undefined)) {
// doesn't immediately resolve to 'string' instead of being deferred.
if (isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(inferredExtendsType))) {
return instantiateType(root.trueType, combinedMapper || mapper);
}
}
@ -10587,13 +10623,20 @@ namespace ts {
return t => t === source ? target : baseMapper(t);
}
function wildcardMapper(type: Type) {
function permissiveMapper(type: Type) {
return type.flags & TypeFlags.TypeParameter ? wildcardType : type;
}
function getRestrictiveTypeParameter(tp: TypeParameter) {
return !tp.constraint ? tp : tp.restrictiveInstantiation || (tp.restrictiveInstantiation = createTypeParameter(tp.symbol));
}
function restrictiveMapper(type: Type) {
return type.flags & TypeFlags.TypeParameter ? getRestrictiveTypeParameter(<TypeParameter>type) : type;
}
function cloneTypeParameter(typeParameter: TypeParameter): TypeParameter {
const result = <TypeParameter>createType(TypeFlags.TypeParameter);
result.symbol = typeParameter.symbol;
const result = createTypeParameter(typeParameter.symbol);
result.target = typeParameter;
return result;
}
@ -10945,9 +10988,14 @@ namespace ts {
return type;
}
function getWildcardInstantiation(type: Type) {
function getPermissiveInstantiation(type: Type) {
return type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) ? type :
type.wildcardInstantiation || (type.wildcardInstantiation = instantiateType(type, wildcardMapper));
type.permissiveInstantiation || (type.permissiveInstantiation = instantiateType(type, permissiveMapper));
}
function getRestrictiveInstantiation(type: Type) {
return type.flags & (TypeFlags.Primitive | TypeFlags.AnyOrUnknown | TypeFlags.Never) ? type :
type.restrictiveInstantiation || (type.restrictiveInstantiation = instantiateType(type, restrictiveMapper));
}
function instantiateIndexInfo(info: IndexInfo | undefined, mapper: TypeMapper): IndexInfo | undefined {
@ -11016,8 +11064,7 @@ namespace ts {
function hasContextSensitiveReturnExpression(node: FunctionLikeDeclaration) {
// TODO(anhans): A block should be context-sensitive if it has a context-sensitive return value.
const body = node.body!;
return body.kind === SyntaxKind.Block ? false : isContextSensitive(body);
return !!node.body && node.body.kind !== SyntaxKind.Block && isContextSensitive(node.body);
}
function isContextSensitiveFunctionOrObjectLiteralMethod(func: Node): func is FunctionExpression | ArrowFunction | MethodDeclaration {
@ -11149,7 +11196,7 @@ namespace ts {
case SyntaxKind.ArrayLiteralExpression:
return elaborateArrayLiteral(node as ArrayLiteralExpression, source, target, relation);
case SyntaxKind.JsxAttributes:
return elaborateJsxAttributes(node as JsxAttributes, source, target, relation);
return elaborateJsxComponents(node as JsxAttributes, source, target, relation);
case SyntaxKind.ArrowFunction:
return elaborateArrowFunction(node as ArrowFunction, source, target, relation);
}
@ -11289,8 +11336,113 @@ namespace ts {
}
}
function elaborateJsxAttributes(node: JsxAttributes, source: Type, target: Type, relation: Map<RelationComparisonResult>) {
return elaborateElementwise(generateJsxAttributes(node), source, target, relation);
function *generateJsxChildren(node: JsxElement, getInvalidTextDiagnostic: () => DiagnosticMessage): ElaborationIterator {
if (!length(node.children)) return;
let memberOffset = 0;
for (let i = 0; i < node.children.length; i++) {
const child = node.children[i];
const nameType = getLiteralType(i - memberOffset);
const elem = getElaborationElementForJsxChild(child, nameType, getInvalidTextDiagnostic);
if (elem) {
yield elem;
}
else {
memberOffset++;
}
}
}
function getElaborationElementForJsxChild(child: JsxChild, nameType: LiteralType, getInvalidTextDiagnostic: () => DiagnosticMessage) {
switch (child.kind) {
case SyntaxKind.JsxExpression:
// child is of the type of the expression
return { errorNode: child, innerExpression: child.expression, nameType };
case SyntaxKind.JsxText:
if (child.containsOnlyWhiteSpaces) {
break; // Whitespace only jsx text isn't real jsx text
}
// child is a string
return { errorNode: child, innerExpression: undefined, nameType, errorMessage: getInvalidTextDiagnostic() };
case SyntaxKind.JsxElement:
case SyntaxKind.JsxSelfClosingElement:
case SyntaxKind.JsxFragment:
// child is of type JSX.Element
return { errorNode: child, innerExpression: child, nameType };
default:
return Debug.assertNever(child, "Found invalid jsx child");
}
}
function elaborateJsxComponents(node: JsxAttributes, source: Type, target: Type, relation: Map<RelationComparisonResult>) {
let result = elaborateElementwise(generateJsxAttributes(node), source, target, relation);
let invalidTextDiagnostic: DiagnosticMessage | undefined;
if (isJsxOpeningElement(node.parent) && isJsxElement(node.parent.parent)) {
const containingElement = node.parent.parent;
const childPropName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node));
const childrenPropName = childPropName === undefined ? "children" : unescapeLeadingUnderscores(childPropName);
const childrenNameType = getLiteralType(childrenPropName);
const childrenTargetType = getIndexedAccessType(target, childrenNameType);
const validChildren = filter(containingElement.children, i => !isJsxText(i) || !i.containsOnlyWhiteSpaces);
if (!length(validChildren)) {
return result;
}
const moreThanOneRealChildren = length(validChildren) > 1;
const arrayLikeTargetParts = filterType(childrenTargetType, isArrayOrTupleLikeType);
const nonArrayLikeTargetParts = filterType(childrenTargetType, t => !isArrayOrTupleLikeType(t));
if (moreThanOneRealChildren) {
if (arrayLikeTargetParts !== neverType) {
const realSource = createTupleType(checkJsxChildren(containingElement, CheckMode.Normal));
result = elaborateElementwise(generateJsxChildren(containingElement, getInvalidTextualChildDiagnostic), realSource, arrayLikeTargetParts, relation) || result;
}
else if (!isTypeRelatedTo(getIndexedAccessType(source, childrenNameType), childrenTargetType, relation)) {
// arity mismatch
result = true;
error(
containingElement.openingElement.tagName,
Diagnostics.This_JSX_tag_s_0_prop_expects_a_single_child_of_type_1_but_multiple_children_were_provided,
childrenPropName,
typeToString(childrenTargetType)
);
}
}
else {
if (nonArrayLikeTargetParts !== neverType) {
const child = validChildren[0];
const elem = getElaborationElementForJsxChild(child, childrenNameType, getInvalidTextualChildDiagnostic);
if (elem) {
result = elaborateElementwise(
(function*() { yield elem; })(),
source,
target,
relation
) || result;
}
}
else if (!isTypeRelatedTo(getIndexedAccessType(source, childrenNameType), childrenTargetType, relation)) {
// arity mismatch
result = true;
error(
containingElement.openingElement.tagName,
Diagnostics.This_JSX_tag_s_0_prop_expects_type_1_which_requires_multiple_children_but_only_a_single_child_was_provided,
childrenPropName,
typeToString(childrenTargetType)
);
}
}
}
return result;
function getInvalidTextualChildDiagnostic() {
if (!invalidTextDiagnostic) {
const tagNameText = getTextOfNode(node.parent.tagName);
const childPropName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node));
const childrenPropName = childPropName === undefined ? "children" : unescapeLeadingUnderscores(childPropName);
const childrenTargetType = getIndexedAccessType(target, getLiteralType(childrenPropName));
const diagnostic = Diagnostics._0_components_don_t_accept_text_as_child_elements_Text_in_JSX_has_the_type_string_but_the_expected_type_of_1_is_2;
invalidTextDiagnostic = { ...diagnostic, key: "!!ALREADY FORMATTED!!", message: formatMessage(/*_dummy*/ undefined, diagnostic, tagNameText, childrenPropName, typeToString(childrenTargetType)) };
}
return invalidTextDiagnostic;
}
}
function *generateLimitedTupleElements(node: ArrayLiteralExpression, target: Type): ElaborationIterator {
@ -11620,8 +11772,7 @@ namespace ts {
if (s & TypeFlags.Undefined && (!strictNullChecks || t & (TypeFlags.Undefined | TypeFlags.Void))) return true;
if (s & TypeFlags.Null && (!strictNullChecks || t & TypeFlags.Null)) return true;
if (s & TypeFlags.Object && t & TypeFlags.NonPrimitive) return true;
if (s & TypeFlags.UniqueESSymbol || t & TypeFlags.UniqueESSymbol) return false;
if (relation === assignableRelation || relation === definitelyAssignableRelation || relation === comparableRelation) {
if (relation === assignableRelation || relation === comparableRelation) {
if (s & TypeFlags.Any) return true;
// Type number or any numeric literal type is assignable to any numeric enum type or any
// numeric enum literal type. This rule exists for backwards compatibility reasons because
@ -11813,7 +11964,7 @@ namespace ts {
target = (<FreshableType>target).regularType;
}
if (source.flags & TypeFlags.Substitution) {
source = relation === definitelyAssignableRelation ? (<SubstitutionType>source).typeVariable : (<SubstitutionType>source).substitute;
source = (<SubstitutionType>source).substitute;
}
if (target.flags & TypeFlags.Substitution) {
target = (<SubstitutionType>target).typeVariable;
@ -11999,7 +12150,7 @@ namespace ts {
}
if (isExcessPropertyCheckTarget(target)) {
const isComparingJsxAttributes = !!(getObjectFlags(source) & ObjectFlags.JsxAttributes);
if ((relation === assignableRelation || relation === definitelyAssignableRelation || relation === comparableRelation) &&
if ((relation === assignableRelation || relation === comparableRelation) &&
(isTypeSubsetOf(globalObjectType, target) || (!isComparingJsxAttributes && isEmptyObjectType(target)))) {
return false;
}
@ -12402,24 +12553,22 @@ namespace ts {
}
// A type S is assignable to keyof T if S is assignable to keyof C, where C is the
// simplified form of T or, if T doesn't simplify, the constraint of T.
if (relation !== definitelyAssignableRelation) {
const simplified = getSimplifiedType((<IndexType>target).type);
const constraint = simplified !== (<IndexType>target).type ? simplified : getConstraintOfType((<IndexType>target).type);
if (constraint) {
// 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;
}
const simplified = getSimplifiedType((<IndexType>target).type);
const constraint = simplified !== (<IndexType>target).type ? simplified : getConstraintOfType((<IndexType>target).type);
if (constraint) {
// 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;
}
}
}
else if (target.flags & TypeFlags.IndexedAccess) {
// A type S is related to a type T[K], where T and K aren't both type variables, if S is related to C,
// where C is the base constraint of T[K]
if (relation !== identityRelation && relation !== definitelyAssignableRelation &&
if (relation !== identityRelation &&
!(isGenericObjectType((<IndexedAccessType>target).objectType) && isGenericIndexType((<IndexedAccessType>target).indexType))) {
const constraint = getBaseConstraintOfType(target);
if (constraint && constraint !== target) {
@ -12462,26 +12611,24 @@ namespace ts {
return result;
}
}
if (relation !== definitelyAssignableRelation) {
const constraint = getConstraintOfType(<TypeParameter>source);
if (!constraint || (source.flags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.Any)) {
// A type variable with no constraint is not related to the non-primitive object type.
if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) {
errorInfo = saveErrorInfo;
return result;
}
}
// hi-speed no-this-instantiation check (less accurate, but avoids costly `this`-instantiation when the constraint will suffice), see #28231 for report on why this is needed
else if (result = isRelatedTo(constraint, target, /*reportErrors*/ false, /*headMessage*/ undefined, isIntersectionConstituent)) {
errorInfo = saveErrorInfo;
return result;
}
// slower, fuller, this-instantiated check (necessary when comparing raw `this` types from base classes), see `subclassWithPolymorphicThisIsAssignable.ts` test for example
else if (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, reportErrors, /*headMessage*/ undefined, isIntersectionConstituent)) {
const constraint = getConstraintOfType(<TypeParameter>source);
if (!constraint || (source.flags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.Any)) {
// A type variable with no constraint is not related to the non-primitive object type.
if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) {
errorInfo = saveErrorInfo;
return result;
}
}
// hi-speed no-this-instantiation check (less accurate, but avoids costly `this`-instantiation when the constraint will suffice), see #28231 for report on why this is needed
else if (result = isRelatedTo(constraint, target, /*reportErrors*/ false, /*headMessage*/ undefined, isIntersectionConstituent)) {
errorInfo = saveErrorInfo;
return result;
}
// slower, fuller, this-instantiated check (necessary when comparing raw `this` types from base classes), see `subclassWithPolymorphicThisIsAssignable.ts` test for example
else if (result = isRelatedTo(getTypeWithThisArgument(constraint, source), target, reportErrors, /*headMessage*/ undefined, isIntersectionConstituent)) {
errorInfo = saveErrorInfo;
return result;
}
}
else if (source.flags & TypeFlags.Index) {
if (result = isRelatedTo(keyofConstraintType, target, reportErrors)) {
@ -12505,7 +12652,7 @@ namespace ts {
}
}
}
else if (relation !== definitelyAssignableRelation) {
else {
const distributiveConstraint = getConstraintOfDistributiveConditionalType(<ConditionalType>source);
if (distributiveConstraint) {
if (result = isRelatedTo(distributiveConstraint, target, reportErrors)) {
@ -12536,9 +12683,6 @@ namespace ts {
}
return Ternary.False;
}
if (relation === definitelyAssignableRelation && isGenericMappedType(source)) {
return Ternary.False;
}
const sourceIsPrimitive = !!(source.flags & TypeFlags.Primitive);
if (relation !== identityRelation) {
source = getApparentType(source);
@ -13438,6 +13582,10 @@ namespace ts {
return isTupleType(type) || !!getPropertyOfType(type, "0" as __String);
}
function isArrayOrTupleLikeType(type: Type): boolean {
return isArrayLikeType(type) || isTupleLikeType(type);
}
function getTupleElementType(type: Type, index: number) {
const propType = getTypeOfPropertyOfType(type, "" + index as __String);
if (propType) {
@ -14741,6 +14889,9 @@ namespace ts {
return symbol !== unknownSymbol ? (isConstraintPosition(node) ? "@" : "") + getSymbolId(symbol) : undefined;
case SyntaxKind.ThisKeyword:
return "0";
case SyntaxKind.NonNullExpression:
case SyntaxKind.ParenthesizedExpression:
return getFlowCacheKey((<NonNullExpression | ParenthesizedExpression>node).expression);
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ElementAccessExpression:
const propName = getAccessedPropertyName(<AccessExpression>node);
@ -14753,6 +14904,11 @@ namespace ts {
}
function isMatchingReference(source: Node, target: Node): boolean {
switch (target.kind) {
case SyntaxKind.ParenthesizedExpression:
case SyntaxKind.NonNullExpression:
return isMatchingReference(source, (target as NonNullExpression | ParenthesizedExpression).expression);
}
switch (source.kind) {
case SyntaxKind.Identifier:
return target.kind === SyntaxKind.Identifier && getResolvedSymbol(<Identifier>source) === getResolvedSymbol(<Identifier>target) ||
@ -14762,6 +14918,9 @@ namespace ts {
return target.kind === SyntaxKind.ThisKeyword;
case SyntaxKind.SuperKeyword:
return target.kind === SyntaxKind.SuperKeyword;
case SyntaxKind.NonNullExpression:
case SyntaxKind.ParenthesizedExpression:
return isMatchingReference((source as NonNullExpression | ParenthesizedExpression).expression, target);
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ElementAccessExpression:
return isAccessExpression(target) &&
@ -14814,17 +14973,8 @@ namespace ts {
}
function isDiscriminantType(type: Type): boolean {
if (type.flags & TypeFlags.Union) {
if (type.flags & (TypeFlags.Boolean | TypeFlags.EnumLiteral)) {
return true;
}
let combined = 0;
for (const t of (<UnionType>type).types) combined |= t.flags;
if (combined & TypeFlags.Unit && !(combined & TypeFlags.Instantiable)) {
return true;
}
}
return false;
return !!(type.flags & TypeFlags.Union &&
(type.flags & (TypeFlags.Boolean | TypeFlags.EnumLiteral) || !isGenericIndexType(type)));
}
function isDiscriminantProperty(type: Type | undefined, name: __String) {
@ -14832,7 +14982,9 @@ namespace ts {
const prop = getUnionOrIntersectionProperty(<UnionType>type, name);
if (prop && getCheckFlags(prop) & CheckFlags.SyntheticProperty) {
if ((<TransientSymbol>prop).isDiscriminantProperty === undefined) {
(<TransientSymbol>prop).isDiscriminantProperty = !!((<TransientSymbol>prop).checkFlags & CheckFlags.HasNonUniformType) && isDiscriminantType(getTypeOfSymbol(prop));
(<TransientSymbol>prop).isDiscriminantProperty =
((<TransientSymbol>prop).checkFlags & CheckFlags.Discriminant) === CheckFlags.Discriminant &&
isDiscriminantType(getTypeOfSymbol(prop));
}
return !!(<TransientSymbol>prop).isDiscriminantProperty;
}
@ -16609,7 +16761,7 @@ namespace ts {
function checkThisBeforeSuper(node: Node, container: Node, diagnosticMessage: DiagnosticMessage) {
const containingClassDecl = <ClassDeclaration>container.parent;
const baseTypeNode = getEffectiveBaseTypeNode(containingClassDecl);
const baseTypeNode = getClassExtendsHeritageElement(containingClassDecl);
// If a containing class does not have extends clause or the class extends null
// skip checking whether super statement is called before "this" accessing.
@ -16958,7 +17110,7 @@ namespace ts {
// at this point the only legal case for parent is ClassLikeDeclaration
const classLikeDeclaration = <ClassLikeDeclaration>container.parent;
if (!getEffectiveBaseTypeNode(classLikeDeclaration)) {
if (!getClassExtendsHeritageElement(classLikeDeclaration)) {
error(node, Diagnostics.super_can_only_be_referenced_in_a_derived_class);
return errorType;
}
@ -17449,11 +17601,23 @@ namespace ts {
return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined;
}
function getContextualTypeForChildJsxExpression(node: JsxElement) {
function getContextualTypeForChildJsxExpression(node: JsxElement, child: JsxChild) {
const attributesType = getApparentTypeOfContextualType(node.openingElement.tagName);
// JSX expression is in children of JSX Element, we will look for an "children" atttribute (we get the name from JSX.ElementAttributesProperty)
const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node));
return attributesType && !isTypeAny(attributesType) && jsxChildrenPropertyName && jsxChildrenPropertyName !== "" ? getTypeOfPropertyOfContextualType(attributesType, jsxChildrenPropertyName) : undefined;
if (!(attributesType && !isTypeAny(attributesType) && jsxChildrenPropertyName && jsxChildrenPropertyName !== "")) {
return undefined;
}
const childIndex = node.children.indexOf(child);
const childFieldType = getTypeOfPropertyOfContextualType(attributesType, jsxChildrenPropertyName);
return childFieldType && mapType(childFieldType, t => {
if (isArrayLikeType(t)) {
return getIndexedAccessType(t, getLiteralType(childIndex));
}
else {
return t;
}
}, /*noReductions*/ true);
}
function getContextualTypeForJsxExpression(node: JsxExpression): Type | undefined {
@ -17461,7 +17625,7 @@ namespace ts {
return isJsxAttributeLike(exprParent)
? getContextualType(node)
: isJsxElement(exprParent)
? getContextualTypeForChildJsxExpression(exprParent)
? getContextualTypeForChildJsxExpression(exprParent, node)
: undefined;
}
@ -19263,8 +19427,8 @@ namespace ts {
}
}
function isValidPropertyAccessForCompletions(node: PropertyAccessExpression | ImportTypeNode, type: Type, property: Symbol): boolean {
return isValidPropertyAccessWithType(node, node.kind !== SyntaxKind.ImportType && node.expression.kind === SyntaxKind.SuperKeyword, property.escapedName, type)
function isValidPropertyAccessForCompletions(node: PropertyAccessExpression | ImportTypeNode | QualifiedName, type: Type, property: Symbol): boolean {
return isValidPropertyAccessWithType(node, node.kind === SyntaxKind.PropertyAccessExpression && node.expression.kind === SyntaxKind.SuperKeyword, property.escapedName, type)
&& (!(property.flags & SymbolFlags.Method) || isValidMethodAccess(property, type));
}
function isValidMethodAccess(method: Symbol, actualThisType: Type): boolean {
@ -20490,9 +20654,9 @@ namespace ts {
* If FuncExpr is of type Any, or of an object type that has no call or construct signatures
* but is a subtype of the Function interface, the call is an untyped function call.
*/
function isUntypedFunctionCall(funcType: Type, apparentFuncType: Type, numCallSignatures: number, numConstructSignatures: number) {
function isUntypedFunctionCall(funcType: Type, apparentFuncType: Type, numCallSignatures: number, numConstructSignatures: number): boolean {
// We exclude union types because we may have a union of function types that happen to have no common signatures.
return isTypeAny(funcType) || isTypeAny(apparentFuncType) && funcType.flags & TypeFlags.TypeParameter ||
return isTypeAny(funcType) || isTypeAny(apparentFuncType) && !!(funcType.flags & TypeFlags.TypeParameter) ||
!numCallSignatures && !numConstructSignatures && !(apparentFuncType.flags & (TypeFlags.Union | TypeFlags.Never)) && isTypeAssignableTo(funcType, globalFunctionType);
}
@ -22810,7 +22974,8 @@ namespace ts {
const type = getTypeOfExpression(initializer, /*cache*/ true);
const widened = getCombinedNodeFlags(declaration) & NodeFlags.Const ||
isDeclarationReadonly(declaration) ||
isTypeAssertion(initializer) ? type : getWidenedLiteralType(type);
isTypeAssertion(initializer) ||
isLiteralOfContextualType(type, getContextualType(initializer)) ? type : getWidenedLiteralType(type);
if (isInJSFile(declaration)) {
if (widened.flags & TypeFlags.Nullable) {
reportImplicitAny(declaration, anyType);
@ -23558,7 +23723,7 @@ namespace ts {
// Constructors of classes with no extends clause may not contain super calls, whereas
// constructors of derived classes must contain at least one super call somewhere in their function body.
const containingClassDecl = <ClassDeclaration>node.parent;
if (getEffectiveBaseTypeNode(containingClassDecl)) {
if (getClassExtendsHeritageElement(containingClassDecl)) {
captureLexicalThis(node.parent, containingClassDecl);
const classExtendsNull = classDeclarationExtendsNull(containingClassDecl);
const superCall = getSuperCallInConstructor(node);
@ -24740,9 +24905,17 @@ namespace ts {
return;
}
if (!containsArgumentsReference(decl)) {
error(node.name,
Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name,
idText(node.name.kind === SyntaxKind.QualifiedName ? node.name.right : node.name));
if (isQualifiedName(node.name)) {
error(node.name,
Diagnostics.Qualified_name_0_is_not_allowed_without_a_leading_param_object_1,
entityNameToString(node.name),
entityNameToString(node.name.left));
}
else {
error(node.name,
Diagnostics.JSDoc_param_tag_has_name_0_but_there_is_no_parameter_with_that_name,
idText(node.name));
}
}
else if (findLast(getJSDocTags(decl), isJSDocParameterTag) === node &&
node.typeExpression && node.typeExpression.type &&
@ -25880,7 +26053,7 @@ namespace ts {
? downlevelIteration
? Diagnostics.Type_0_is_not_an_array_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator
: isIterable
? Diagnostics.Type_0_is_not_an_array_type_Use_compiler_option_downlevelIteration_to_allow_iterating_of_iterators
? Diagnostics.Type_0_is_not_an_array_type_or_a_string_type_Use_compiler_option_downlevelIteration_to_allow_iterating_of_iterators
: Diagnostics.Type_0_is_not_an_array_type
: downlevelIteration
? Diagnostics.Type_0_is_not_an_array_type_or_a_string_type_or_does_not_have_a_Symbol_iterator_method_that_returns_an_iterator
@ -26465,6 +26638,7 @@ namespace ts {
if (produceDiagnostics) {
if (node.default) {
seenDefault = true;
checkTypeParametersNotReferenced(node.default, typeParameterDeclarations, i);
}
else if (seenDefault) {
error(node, Diagnostics.Required_type_parameters_may_not_follow_optional_type_parameters);
@ -26479,6 +26653,24 @@ namespace ts {
}
}
/** Check that type parameter defaults only reference previously declared type parameters */
function checkTypeParametersNotReferenced(root: TypeNode, typeParameters: ReadonlyArray<TypeParameterDeclaration>, index: number) {
visit(root);
function visit(node: Node) {
if (node.kind === SyntaxKind.TypeReference) {
const type = getTypeFromTypeReference(<TypeReferenceNode>node);
if (type.flags & TypeFlags.TypeParameter) {
for (let i = index; i < typeParameters.length; i++) {
if (type.symbol === getSymbolOfNode(typeParameters[i])) {
error(node, Diagnostics.Type_parameter_defaults_can_only_reference_previously_declared_type_parameters);
}
}
}
}
forEachChild(node, visit);
}
}
/** Check that type parameter lists are identical across multiple declarations */
function checkTypeParameterListsIdentical(symbol: Symbol) {
if (symbol.declarations.length === 1) {
@ -29932,10 +30124,6 @@ namespace ts {
checkGrammarForDisallowedTrailingComma(parameters, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma);
}
if (isBindingPattern(parameter.name)) {
return grammarErrorOnNode(parameter.name, Diagnostics.A_rest_element_cannot_contain_a_binding_pattern);
}
if (parameter.questionToken) {
return grammarErrorOnNode(parameter.questionToken, Diagnostics.A_rest_parameter_cannot_be_optional);
}

View file

@ -1776,7 +1776,7 @@
"category": "Error",
"code": 2496
},
"Module '{0}' resolves to a non-module entity and cannot be imported using this construct.": {
"This module can only be referenced with ECMAScript imports/exports by turning on the '{0}' flag and referencing its default export.": {
"category": "Error",
"code": 2497
},
@ -2056,10 +2056,6 @@
"category": "Error",
"code": 2567
},
"Type '{0}' is not an array type. Use compiler option '--downlevelIteration' to allow iterating of iterators.": {
"category": "Error",
"code": 2568
},
"Type '{0}' is not an array type or a string type. Use compiler option '--downlevelIteration' to allow iterating of iterators.": {
"category": "Error",
"code": 2569
@ -2537,6 +2533,22 @@
"category": "Error",
"code": 2743
},
"Type parameter defaults can only reference previously declared type parameters.": {
"category": "Error",
"code": 2744
},
"This JSX tag's '{0}' prop expects type '{1}' which requires multiple children, but only a single child was provided.": {
"category": "Error",
"code": 2745
},
"This JSX tag's '{0}' prop expects a single child of type '{1}', but multiple children were provided.": {
"category": "Error",
"code": 2746
},
"'{0}' components don't accept text as child elements. Text in JSX has the type 'string', but the expected type of '{1}' is '{2}'.": {
"category": "Error",
"code": 2747
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
@ -4262,6 +4274,10 @@
"category": "Error",
"code": 8031
},
"Qualified name '{0}' is not allowed without a leading '@param {object} {1}'.": {
"category": "Error",
"code": 8032
},
"Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clause.": {
"category": "Error",
"code": 9002
@ -4807,5 +4823,9 @@
"Add names to all parameters without names": {
"category": "Message",
"code": 95073
},
"Enable the 'experimentalDecorators' option in your configuration file": {
"category": "Message",
"code": 95074
}
}

View file

@ -2561,6 +2561,7 @@ namespace ts {
function emitJsxSelfClosingElement(node: JsxSelfClosingElement) {
writePunctuation("<");
emitJsxTagName(node.tagName);
emitTypeArguments(node, node.typeArguments);
writeSpace();
emit(node.attributes);
writePunctuation("/>");
@ -2577,6 +2578,7 @@ namespace ts {
if (isJsxOpeningElement(node)) {
emitJsxTagName(node.tagName);
emitTypeArguments(node, node.typeArguments);
if (node.attributes.properties && node.attributes.properties.length > 0) {
writeSpace();
}
@ -4389,7 +4391,7 @@ namespace ts {
return;
}
const { line: sourceLine, character: sourceCharacter } = getLineAndCharacterOfPosition(currentSourceFile!, pos);
const { line: sourceLine, character: sourceCharacter } = getLineAndCharacterOfPosition(sourceMapSource, pos);
sourceMapGenerator!.addMapping(
writer.getLine(),
writer.getColumn(),

View file

@ -7774,17 +7774,18 @@ namespace ts {
const libReferenceDirectives = context.libReferenceDirectives;
forEach(toArray(entryOrList), (arg: PragmaPseudoMap["reference"]) => {
// TODO: GH#18217
const { types, lib, path } = arg!.arguments;
if (arg!.arguments["no-default-lib"]) {
context.hasNoDefaultLib = true;
}
else if (arg!.arguments.types) {
typeReferenceDirectives.push({ pos: arg!.arguments.types!.pos, end: arg!.arguments.types!.end, fileName: arg!.arguments.types!.value });
else if (types) {
typeReferenceDirectives.push({ pos: types.pos, end: types.end, fileName: types.value });
}
else if (arg!.arguments.lib) {
libReferenceDirectives.push({ pos: arg!.arguments.lib!.pos, end: arg!.arguments.lib!.end, fileName: arg!.arguments.lib!.value });
else if (lib) {
libReferenceDirectives.push({ pos: lib.pos, end: lib.end, fileName: lib.value });
}
else if (arg!.arguments.path) {
referencedFiles.push({ pos: arg!.arguments.path!.pos, end: arg!.arguments.path!.end, fileName: arg!.arguments.path!.value });
else if (path) {
referencedFiles.push({ pos: path.pos, end: path.end, fileName: path.value });
}
else {
reportDiagnostic(arg!.range.pos, arg!.range.end - arg!.range.pos, Diagnostics.Invalid_reference_directive_syntax);

View file

@ -2227,8 +2227,9 @@ namespace ts {
processReferencedFiles(file, isDefaultLib);
processTypeReferenceDirectives(file);
}
processLibReferenceDirectives(file);
if (!options.noLib) {
processLibReferenceDirectives(file);
}
modulesWithElidedImports.set(file.path, false);
processImportedModules(file);
@ -2315,8 +2316,10 @@ namespace ts {
processReferencedFiles(file, isDefaultLib);
processTypeReferenceDirectives(file);
}
if (!options.noLib) {
processLibReferenceDirectives(file);
}
processLibReferenceDirectives(file);
// always process imported modules to record module name resolutions
processImportedModules(file);

View file

@ -634,7 +634,10 @@ namespace ts {
if (!isLateVisibilityPaintedStatement(i)) {
return Debug.fail(`Late replaced statement was found which is not handled by the declaration transformer!: ${(ts as any).SyntaxKind ? (ts as any).SyntaxKind[(i as any).kind] : (i as any).kind}`);
}
const priorNeedsDeclare = needsDeclare;
needsDeclare = i.parent && isSourceFile(i.parent) && !(isExternalModule(i.parent) && isBundledEmit);
const result = transformTopLevelDeclaration(i, /*privateDeclaration*/ true);
needsDeclare = priorNeedsDeclare;
lateStatementReplacementMap.set("" + getOriginalNodeId(i), result);
}

View file

@ -780,7 +780,7 @@ namespace ts {
enableSubstitutionsForBlockScopedBindings();
}
const extendsClauseElement = getEffectiveBaseTypeNode(node);
const extendsClauseElement = getClassExtendsHeritageElement(node);
const classFunction = createFunctionExpression(
/*modifiers*/ undefined,
/*asteriskToken*/ undefined,
@ -1350,8 +1350,8 @@ namespace ts {
* part of a constructor declaration with a
* synthesized call to `super`
*/
function shouldAddRestParameter(node: ParameterDeclaration | undefined, inConstructorWithSynthesizedSuper: boolean) {
return node && node.dotDotDotToken && node.name.kind === SyntaxKind.Identifier && !inConstructorWithSynthesizedSuper;
function shouldAddRestParameter(node: ParameterDeclaration | undefined, inConstructorWithSynthesizedSuper: boolean): node is ParameterDeclaration {
return !!(node && node.dotDotDotToken && !inConstructorWithSynthesizedSuper);
}
/**
@ -1370,11 +1370,11 @@ namespace ts {
}
// `declarationName` is the name of the local declaration for the parameter.
const declarationName = getMutableClone(<Identifier>parameter!.name);
const declarationName = parameter.name.kind === SyntaxKind.Identifier ? getMutableClone(parameter.name) : createTempVariable(/*recordTempVariable*/ undefined);
setEmitFlags(declarationName, EmitFlags.NoSourceMap);
// `expressionName` is the name of the parameter used in expressions.
const expressionName = getSynthesizedClone(<Identifier>parameter!.name);
const expressionName = parameter.name.kind === SyntaxKind.Identifier ? getSynthesizedClone(parameter.name) : declarationName;
const restIndex = node.parameters.length - 1;
const temp = createLoopVariable();
@ -1439,6 +1439,24 @@ namespace ts {
setEmitFlags(forStatement, EmitFlags.CustomPrologue);
startOnNewLine(forStatement);
statements.push(forStatement);
if (parameter.name.kind !== SyntaxKind.Identifier) {
// do the actual destructuring of the rest parameter if necessary
statements.push(
setEmitFlags(
setTextRange(
createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList(
flattenDestructuringBinding(parameter, visitor, context, FlattenLevel.All, expressionName),
)
),
parameter
),
EmitFlags.CustomPrologue
)
);
}
}
/**

View file

@ -1898,6 +1898,7 @@ namespace ts {
case SyntaxKind.StringLiteral:
return createIdentifier("String");
case SyntaxKind.PrefixUnaryExpression:
case SyntaxKind.NumericLiteral:
return createIdentifier("Number");

View file

@ -3037,8 +3037,10 @@ namespace ts {
/* @internal */ typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker): TypeNode | undefined; // tslint:disable-line unified-signatures
/** Note that the resulting nodes cannot be checked. */
signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration & {typeArguments?: NodeArray<TypeNode>} | undefined;
/* @internal */ signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker): SignatureDeclaration & {typeArguments?: NodeArray<TypeNode>} | undefined; // tslint:disable-line unified-signatures
/** Note that the resulting nodes cannot be checked. */
indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): IndexSignatureDeclaration | undefined;
/* @internal */ indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags, tracker?: SymbolTracker): IndexSignatureDeclaration | undefined; // tslint:disable-line unified-signatures
/** Note that the resulting nodes cannot be checked. */
symbolToEntityName(symbol: Symbol, meaning: SymbolFlags, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): EntityName | undefined;
/** Note that the resulting nodes cannot be checked. */
@ -3108,7 +3110,7 @@ namespace ts {
getConstantValue(node: EnumMember | PropertyAccessExpression | ElementAccessExpression): string | number | undefined;
isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName | ImportTypeNode, propertyName: string): boolean;
/** Exclude accesses to private properties or methods with a `this` parameter that `type` doesn't satisfy. */
/* @internal */ isValidPropertyAccessForCompletions(node: PropertyAccessExpression | ImportTypeNode, type: Type, property: Symbol): boolean;
/* @internal */ isValidPropertyAccessForCompletions(node: PropertyAccessExpression | ImportTypeNode | QualifiedName, type: Type, property: Symbol): boolean;
/** Follow all aliases to get the original symbol. */
getAliasedSymbol(symbol: Symbol): Symbol;
/** Follow a *single* alias to get the immediately aliased symbol. */
@ -3677,15 +3679,17 @@ namespace ts {
Readonly = 1 << 3, // Readonly transient symbol
Partial = 1 << 4, // Synthetic property present in some but not all constituents
HasNonUniformType = 1 << 5, // Synthetic property with non-uniform type in constituents
ContainsPublic = 1 << 6, // Synthetic property with public constituent(s)
ContainsProtected = 1 << 7, // Synthetic property with protected constituent(s)
ContainsPrivate = 1 << 8, // Synthetic property with private constituent(s)
ContainsStatic = 1 << 9, // Synthetic property with static constituent(s)
Late = 1 << 10, // Late-bound symbol for a computed property with a dynamic name
ReverseMapped = 1 << 11, // Property of reverse-inferred homomorphic mapped type
OptionalParameter = 1 << 12, // Optional parameter
RestParameter = 1 << 13, // Rest parameter
Synthetic = SyntheticProperty | SyntheticMethod
HasLiteralType = 1 << 6, // Synthetic property with at least one literal type in constituents
ContainsPublic = 1 << 7, // Synthetic property with public constituent(s)
ContainsProtected = 1 << 8, // Synthetic property with protected constituent(s)
ContainsPrivate = 1 << 9, // Synthetic property with private constituent(s)
ContainsStatic = 1 << 10, // Synthetic property with static constituent(s)
Late = 1 << 11, // Late-bound symbol for a computed property with a dynamic name
ReverseMapped = 1 << 12, // Property of reverse-inferred homomorphic mapped type
OptionalParameter = 1 << 13, // Optional parameter
RestParameter = 1 << 14, // Rest parameter
Synthetic = SyntheticProperty | SyntheticMethod,
Discriminant = HasNonUniformType | HasLiteralType
}
/* @internal */
@ -3914,7 +3918,9 @@ namespace ts {
aliasTypeArguments?: ReadonlyArray<Type>; // Alias type arguments (if any)
/* @internal */ aliasTypeArgumentsContainsMarker?: boolean; // Alias type arguments (if any)
/* @internal */
wildcardInstantiation?: Type; // Instantiation with type parameters mapped to wildcard type
permissiveInstantiation?: Type; // Instantiation with type parameters mapped to wildcard type
/* @internal */
restrictiveInstantiation?: Type; // Instantiation with type parameters mapped to unconstrained form
/* @internal */
immediateBaseConstraint?: Type; // Immediate base constraint cache
}

View file

@ -888,7 +888,7 @@ namespace ts {
}
const isMissing = nodeIsMissing(errorNode);
const pos = isMissing
const pos = isMissing || isJsxText(node)
? errorNode.pos
: skipTrivia(sourceFile.text, errorNode.pos);
@ -2121,7 +2121,7 @@ namespace ts {
: undefined;
}
function getSingleInitializerOfVariableStatementOrPropertyDeclaration(node: Node): Expression | undefined {
export function getSingleInitializerOfVariableStatementOrPropertyDeclaration(node: Node): Expression | undefined {
switch (node.kind) {
case SyntaxKind.VariableStatement:
const v = getSingleVariableOfVariableStatement(node);
@ -7026,6 +7026,7 @@ namespace ts {
};
}
export function formatMessage(_dummy: any, message: DiagnosticMessage, ...args: (string | number | undefined)[]): string;
export function formatMessage(_dummy: any, message: DiagnosticMessage): string {
let text = getLocaleSpecificMessage(message);

View file

@ -384,7 +384,8 @@ namespace ts.server {
return notImplemented();
}
getRenameInfo(fileName: string, position: number, findInStrings?: boolean, findInComments?: boolean): RenameInfo {
getRenameInfo(fileName: string, position: number, _options?: RenameInfoOptions, findInStrings?: boolean, findInComments?: boolean): RenameInfo {
// Not passing along 'options' because server should already have those from the 'configure' command
const args: protocol.RenameRequestArgs = { ...this.createFileLocationRequestArgs(fileName, position), findInStrings, findInComments };
const request = this.processRequest<protocol.RenameRequest>(CommandNames.Rename, args);
@ -428,7 +429,7 @@ namespace ts.server {
this.lastRenameEntry.inputs.position !== position ||
this.lastRenameEntry.inputs.findInStrings !== findInStrings ||
this.lastRenameEntry.inputs.findInComments !== findInComments) {
this.getRenameInfo(fileName, position, findInStrings, findInComments);
this.getRenameInfo(fileName, position, { allowRenameOfImportPath: true }, findInStrings, findInComments);
}
return this.lastRenameEntry!.locations;

View file

@ -183,8 +183,9 @@ namespace compiler {
}
public getSourceMapRecord(): string | undefined {
if (this.result!.sourceMaps && this.result!.sourceMaps!.length > 0) {
return Harness.SourceMapRecorder.getSourceMapRecord(this.result!.sourceMaps!, this.program!, Array.from(this.js.values()).filter(d => !ts.fileExtensionIs(d.file, ts.Extension.Json)), Array.from(this.dts.values()));
const maps = this.result!.sourceMaps;
if (maps && maps.length > 0) {
return Harness.SourceMapRecorder.getSourceMapRecord(maps, this.program!, Array.from(this.js.values()).filter(d => !ts.fileExtensionIs(d.file, ts.Extension.Json)), Array.from(this.dts.values()));
}
}

View file

@ -1308,8 +1308,8 @@ Actual: ${stringify(fullActual)}`);
}
}
public verifyRenameInfoSucceeded(displayName: string | undefined, fullDisplayName: string | undefined, kind: string | undefined, kindModifiers: string | undefined, fileToRename: string | undefined, expectedRange: Range | undefined): void {
const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition);
public verifyRenameInfoSucceeded(displayName: string | undefined, fullDisplayName: string | undefined, kind: string | undefined, kindModifiers: string | undefined, fileToRename: string | undefined, expectedRange: Range | undefined, renameInfoOptions: ts.RenameInfoOptions | undefined): void {
const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition, renameInfoOptions || { allowRenameOfImportPath: true });
if (!renameInfo.canRename) {
throw this.raiseError("Rename did not succeed");
}
@ -1334,8 +1334,9 @@ Actual: ${stringify(fullActual)}`);
}
}
public verifyRenameInfoFailed(message?: string) {
const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition);
public verifyRenameInfoFailed(message?: string, allowRenameOfImportPath?: boolean) {
allowRenameOfImportPath = allowRenameOfImportPath === undefined ? true : allowRenameOfImportPath;
const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition, { allowRenameOfImportPath });
if (renameInfo.canRename) {
throw this.raiseError("Rename was expected to fail");
}
@ -4091,12 +4092,12 @@ namespace FourSlashInterface {
this.state.verifySemanticClassifications(classifications);
}
public renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string, fileToRename?: string, expectedRange?: FourSlash.Range) {
this.state.verifyRenameInfoSucceeded(displayName, fullDisplayName, kind, kindModifiers, fileToRename, expectedRange);
public renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string, fileToRename?: string, expectedRange?: FourSlash.Range, options?: ts.RenameInfoOptions) {
this.state.verifyRenameInfoSucceeded(displayName, fullDisplayName, kind, kindModifiers, fileToRename, expectedRange, options);
}
public renameInfoFailed(message?: string) {
this.state.verifyRenameInfoFailed(message);
public renameInfoFailed(message?: string, allowRenameOfImportPath?: boolean) {
this.state.verifyRenameInfoFailed(message, allowRenameOfImportPath);
}
public renameLocations(startRanges: ArrayOrSingle<FourSlash.Range>, options: RenameLocationsOptions) {

View file

@ -469,8 +469,8 @@ namespace Harness.LanguageService {
getSignatureHelpItems(fileName: string, position: number, options: ts.SignatureHelpItemsOptions | undefined): ts.SignatureHelpItems {
return unwrapJSONCallResult(this.shim.getSignatureHelpItems(fileName, position, options));
}
getRenameInfo(fileName: string, position: number): ts.RenameInfo {
return unwrapJSONCallResult(this.shim.getRenameInfo(fileName, position));
getRenameInfo(fileName: string, position: number, options?: ts.RenameInfoOptions): ts.RenameInfo {
return unwrapJSONCallResult(this.shim.getRenameInfo(fileName, position, options));
}
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ts.RenameLocation[] {
return unwrapJSONCallResult(this.shim.findRenameLocations(fileName, position, findInStrings, findInComments));

View file

@ -2083,7 +2083,7 @@
<Str Cat="Text">
<Val><![CDATA[Cannot find the common subdirectory path for the input files.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[找不到輸入檔的一般子目錄路徑。]]></Val>
<Val><![CDATA[找不到輸入檔的一般子目錄路徑。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@ -7567,7 +7567,7 @@
<Str Cat="Text">
<Val><![CDATA[Specify the root directory of input files. Use to control the output directory structure with --outDir.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[指定輸入檔的根目錄。用以控制具有 --outDir 的輸出目錄結構。]]></Val>
<Val><![CDATA[指定輸入檔的根目錄。用以控制具有 --outDir 的輸出目錄結構。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@ -9172,7 +9172,7 @@
<Str Cat="Text">
<Val><![CDATA[Watch input files.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[監看輸入檔。]]></Val>
<Val><![CDATA[監看輸入檔。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />

View file

@ -1277,7 +1277,8 @@ namespace ts.server {
private setConfigFileExistenceByNewConfiguredProject(project: ConfiguredProject) {
const configFileExistenceInfo = this.getConfigFileExistenceInfo(project);
if (configFileExistenceInfo) {
Debug.assert(configFileExistenceInfo.exists);
// The existance might not be set if the file watcher is not invoked by the time config project is created by external project
configFileExistenceInfo.exists = true;
// close existing watcher
if (configFileExistenceInfo.configFileWatcherForRootOfInferredProject) {
const configFileName = project.getConfigFilePath();
@ -2007,7 +2008,7 @@ namespace ts.server {
const path = toNormalizedPath(uncheckedFileName);
const info = this.getScriptInfoForNormalizedPath(path);
if (info) return info;
const configProject = this.configuredProjects.get(uncheckedFileName);
const configProject = this.configuredProjects.get(this.toPath(uncheckedFileName));
return configProject && configProject.getCompilerOptions().configFile;
}
@ -2776,7 +2777,12 @@ namespace ts.server {
return;
}
const info: OpenFileInfo = { checkJs: !!scriptInfo.getDefaultProject().getSourceFile(scriptInfo.path)!.checkJsDirective };
const project = scriptInfo.getDefaultProject();
if (!project.languageServiceEnabled) {
return;
}
const info: OpenFileInfo = { checkJs: !!project.getSourceFile(scriptInfo.path)!.checkJsDirective };
this.eventHandler({ eventName: OpenFileInfoTelemetryEvent, data: { info } });
}

View file

@ -2905,6 +2905,7 @@ namespace ts.server.protocol {
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
readonly allowTextChangesInNewFiles?: boolean;
readonly lazyConfiguredProjectsFromExternalProject?: boolean;
readonly allowRenameOfImportPath?: boolean;
}
export interface CompilerOptions {

View file

@ -1177,7 +1177,8 @@ namespace ts.server {
private getRenameInfo(args: protocol.FileLocationRequestArgs): RenameInfo {
const { file, project } = this.getFileAndProject(args);
const position = this.getPositionInFile(args, file);
return project.getLanguageService().getRenameInfo(file, position);
const preferences = this.getHostPreferences();
return project.getLanguageService().getRenameInfo(file, position, { allowRenameOfImportPath: preferences.allowRenameOfImportPath });
}
private getProjects(args: protocol.FileRequestArgs, getScriptInfoEnsuringProjectsUptoDate?: boolean, ignoreNoProjectError?: boolean): Projects {
@ -1236,7 +1237,7 @@ namespace ts.server {
if (!simplifiedResult) return locations;
const defaultProject = this.getDefaultProject(args);
const renameInfo: protocol.RenameInfo = this.mapRenameInfo(defaultProject.getLanguageService().getRenameInfo(file, position), Debug.assertDefined(this.projectService.getScriptInfo(file)));
const renameInfo: protocol.RenameInfo = this.mapRenameInfo(defaultProject.getLanguageService().getRenameInfo(file, position, { allowRenameOfImportPath: this.getHostPreferences().allowRenameOfImportPath }), Debug.assertDefined(this.projectService.getScriptInfo(file)));
return { info: renameInfo, locs: this.toSpanGroups(locations) };
}

View file

@ -275,7 +275,7 @@ namespace ts.codefix {
inJs: boolean,
preferences: UserPreferences,
): void {
const methodDeclaration = createMethodFromCallExpression(context, callExpression, token.text, inJs, makeStatic, preferences, !isInterfaceDeclaration(typeDecl));
const methodDeclaration = createMethodFromCallExpression(context, callExpression, token.text, inJs, makeStatic, preferences, typeDecl);
const containingMethodDeclaration = getAncestor(callExpression, SyntaxKind.MethodDeclaration);
if (containingMethodDeclaration && containingMethodDeclaration.parent === typeDecl) {

View file

@ -74,7 +74,7 @@ namespace ts.codefix {
const tsconfigObjectLiteral = getTsConfigObjectLiteralExpression(configFile);
if (!tsconfigObjectLiteral) return undefined;
const compilerOptionsProperty = findProperty(tsconfigObjectLiteral, "compilerOptions");
const compilerOptionsProperty = findJsonProperty(tsconfigObjectLiteral, "compilerOptions");
if (!compilerOptionsProperty) {
const newCompilerOptions = createObjectLiteral([makeDefaultBaseUrl(), makeDefaultPaths()]);
changes.insertNodeAtObjectStart(configFile, tsconfigObjectLiteral, createJsonPropertyAssignment("compilerOptions", newCompilerOptions));
@ -94,7 +94,7 @@ namespace ts.codefix {
return createJsonPropertyAssignment("baseUrl", createStringLiteral(defaultBaseUrl));
}
function getOrAddBaseUrl(changes: textChanges.ChangeTracker, tsconfig: TsConfigSourceFile, compilerOptions: ObjectLiteralExpression): string {
const baseUrlProp = findProperty(compilerOptions, "baseUrl");
const baseUrlProp = findJsonProperty(compilerOptions, "baseUrl");
if (baseUrlProp) {
return isStringLiteral(baseUrlProp.initializer) ? baseUrlProp.initializer.text : defaultBaseUrl;
}
@ -112,7 +112,7 @@ namespace ts.codefix {
return createJsonPropertyAssignment("paths", createObjectLiteral([makeDefaultPathMapping()]));
}
function getOrAddPathMapping(changes: textChanges.ChangeTracker, tsconfig: TsConfigSourceFile, compilerOptions: ObjectLiteralExpression) {
const paths = findProperty(compilerOptions, "paths");
const paths = findJsonProperty(compilerOptions, "paths");
if (!paths || !isObjectLiteralExpression(paths.initializer)) {
changes.insertNodeAtObjectStart(tsconfig, compilerOptions, makeDefaultPaths());
return defaultTypesDirectoryName;
@ -129,14 +129,6 @@ namespace ts.codefix {
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 };
}

View file

@ -8,9 +8,9 @@ namespace ts.codefix {
registerCodeFix({
errorCodes,
getCodeActions(context) {
const { program, sourceFile, span } = context;
const { sourceFile, span } = context;
const changes = textChanges.ChangeTracker.with(context, t =>
addMissingMembers(getClass(sourceFile, span.start), sourceFile, program.getTypeChecker(), t, context.preferences));
addMissingMembers(getClass(sourceFile, span.start), sourceFile, context, t, context.preferences));
return changes.length === 0 ? undefined : [createCodeFixAction(fixId, changes, Diagnostics.Implement_inherited_abstract_class, fixId, Diagnostics.Implement_all_inherited_abstract_classes)];
},
fixIds: [fixId],
@ -19,7 +19,7 @@ namespace ts.codefix {
return codeFixAll(context, errorCodes, (changes, diag) => {
const classDeclaration = getClass(diag.file, diag.start);
if (addToSeen(seenClassDeclarations, getNodeId(classDeclaration))) {
addMissingMembers(classDeclaration, context.sourceFile, context.program.getTypeChecker(), changes, context.preferences);
addMissingMembers(classDeclaration, context.sourceFile, context, changes, context.preferences);
}
});
},
@ -32,15 +32,16 @@ namespace ts.codefix {
return cast(token.parent, isClassLike);
}
function addMissingMembers(classDeclaration: ClassLikeDeclaration, sourceFile: SourceFile, checker: TypeChecker, changeTracker: textChanges.ChangeTracker, preferences: UserPreferences): void {
function addMissingMembers(classDeclaration: ClassLikeDeclaration, sourceFile: SourceFile, context: TypeConstructionContext, changeTracker: textChanges.ChangeTracker, preferences: UserPreferences): void {
const extendsNode = getEffectiveBaseTypeNode(classDeclaration)!;
const checker = context.program.getTypeChecker();
const instantiatedExtendsType = checker.getTypeAtLocation(extendsNode);
// Note that this is ultimately derived from a map indexed by symbol names,
// so duplicates cannot occur.
const abstractAndNonPrivateExtendsSymbols = checker.getPropertiesOfType(instantiatedExtendsType).filter(symbolPointsToNonPrivateAndAbstractMember);
createMissingMemberNodes(classDeclaration, abstractAndNonPrivateExtendsSymbols, checker, preferences, member => changeTracker.insertNodeAtClassStart(sourceFile, classDeclaration, member));
createMissingMemberNodes(classDeclaration, abstractAndNonPrivateExtendsSymbols, context, preferences, member => changeTracker.insertNodeAtClassStart(sourceFile, classDeclaration, member));
}
function symbolPointsToNonPrivateAndAbstractMember(symbol: Symbol): boolean {

View file

@ -6,11 +6,10 @@ namespace ts.codefix {
registerCodeFix({
errorCodes,
getCodeActions(context) {
const { program, sourceFile, span } = context;
const { sourceFile, span } = context;
const classDeclaration = getClass(sourceFile, span.start);
const checker = program.getTypeChecker();
return mapDefined<ExpressionWithTypeArguments, CodeFixAction>(getClassImplementsHeritageClauseElements(classDeclaration), implementedTypeNode => {
const changes = textChanges.ChangeTracker.with(context, t => addMissingDeclarations(checker, implementedTypeNode, sourceFile, classDeclaration, t, context.preferences));
const changes = textChanges.ChangeTracker.with(context, t => addMissingDeclarations(context, implementedTypeNode, sourceFile, classDeclaration, t, context.preferences));
return changes.length === 0 ? undefined : createCodeFixAction(fixId, changes, [Diagnostics.Implement_interface_0, implementedTypeNode.getText(sourceFile)], fixId, Diagnostics.Implement_all_unimplemented_interfaces);
});
},
@ -21,7 +20,7 @@ namespace ts.codefix {
const classDeclaration = getClass(diag.file, diag.start);
if (addToSeen(seenClassDeclarations, getNodeId(classDeclaration))) {
for (const implementedTypeNode of getClassImplementsHeritageClauseElements(classDeclaration)!) {
addMissingDeclarations(context.program.getTypeChecker(), implementedTypeNode, diag.file, classDeclaration, changes, context.preferences);
addMissingDeclarations(context, implementedTypeNode, diag.file, classDeclaration, changes, context.preferences);
}
}
});
@ -37,13 +36,14 @@ namespace ts.codefix {
}
function addMissingDeclarations(
checker: TypeChecker,
context: TypeConstructionContext,
implementedTypeNode: ExpressionWithTypeArguments,
sourceFile: SourceFile,
classDeclaration: ClassLikeDeclaration,
changeTracker: textChanges.ChangeTracker,
preferences: UserPreferences,
): void {
const checker = context.program.getTypeChecker();
const maybeHeritageClauseSymbol = getHeritageClauseSymbolTable(classDeclaration, checker);
// Note that this is ultimately derived from a map indexed by symbol names,
// so duplicates cannot occur.
@ -60,12 +60,12 @@ namespace ts.codefix {
createMissingIndexSignatureDeclaration(implementedType, IndexKind.String);
}
createMissingMemberNodes(classDeclaration, nonPrivateAndNotExistedInHeritageClauseMembers, checker, preferences, member => changeTracker.insertNodeAtClassStart(sourceFile, classDeclaration, member));
createMissingMemberNodes(classDeclaration, nonPrivateAndNotExistedInHeritageClauseMembers, context, preferences, member => changeTracker.insertNodeAtClassStart(sourceFile, classDeclaration, member));
function createMissingIndexSignatureDeclaration(type: InterfaceType, kind: IndexKind): void {
const indexInfoOfKind = checker.getIndexInfoOfType(type, kind);
if (indexInfoOfKind) {
changeTracker.insertNodeAtClassStart(sourceFile, classDeclaration, checker.indexInfoToIndexSignatureDeclaration(indexInfoOfKind, kind, classDeclaration)!);
changeTracker.insertNodeAtClassStart(sourceFile, classDeclaration, checker.indexInfoToIndexSignatureDeclaration(indexInfoOfKind, kind, classDeclaration, /*flags*/ undefined, getNoopSymbolTrackerWithResolver(context))!);
}
}
}

View file

@ -0,0 +1,24 @@
/* @internal */
namespace ts.codefix {
const fixId = "enableExperimentalDecorators";
const errorCodes = [
Diagnostics.Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Set_the_experimentalDecorators_option_to_remove_this_warning.code
];
registerCodeFix({
errorCodes,
getCodeActions: (context) => {
const { configFile } = context.program.getCompilerOptions();
if (configFile === undefined) {
return undefined;
}
const changes = textChanges.ChangeTracker.with(context, changeTracker => makeChange(changeTracker, configFile));
return [createCodeFixActionNoFixId(fixId, changes, Diagnostics.Enable_the_experimentalDecorators_option_in_your_configuration_file)];
},
fixIds: [fixId],
});
function makeChange(changeTracker: textChanges.ChangeTracker, configFile: TsConfigSourceFile) {
setJsonCompilerOptionValue(changeTracker, configFile, "experimentalDecorators", createTrue());
}
}

View file

@ -6,23 +6,48 @@ namespace ts.codefix {
* @param possiblyMissingSymbols The collection of symbols to filter and then get insertions for.
* @returns Empty string iff there are no member insertions.
*/
export function createMissingMemberNodes(classDeclaration: ClassLikeDeclaration, possiblyMissingSymbols: ReadonlyArray<Symbol>, checker: TypeChecker, preferences: UserPreferences, out: (node: ClassElement) => void): void {
export function createMissingMemberNodes(classDeclaration: ClassLikeDeclaration, possiblyMissingSymbols: ReadonlyArray<Symbol>, context: TypeConstructionContext, preferences: UserPreferences, out: (node: ClassElement) => void): void {
const classMembers = classDeclaration.symbol.members!;
for (const symbol of possiblyMissingSymbols) {
if (!classMembers.has(symbol.escapedName)) {
addNewNodeForMemberSymbol(symbol, classDeclaration, checker, preferences, out);
addNewNodeForMemberSymbol(symbol, classDeclaration, context, preferences, out);
}
}
}
function getModuleSpecifierResolverHost(context: TypeConstructionContext): SymbolTracker["moduleResolverHost"] {
return {
directoryExists: context.host.directoryExists ? d => context.host.directoryExists!(d) : undefined,
fileExists: context.host.fileExists ? f => context.host.fileExists!(f) : undefined,
getCurrentDirectory: context.host.getCurrentDirectory ? () => context.host.getCurrentDirectory!() : undefined,
readFile: context.host.readFile ? f => context.host.readFile!(f) : undefined,
useCaseSensitiveFileNames: context.host.useCaseSensitiveFileNames ? () => context.host.useCaseSensitiveFileNames!() : undefined,
getSourceFiles: () => context.program.getSourceFiles(),
getCommonSourceDirectory: () => context.program.getCommonSourceDirectory(),
};
}
export function getNoopSymbolTrackerWithResolver(context: TypeConstructionContext): SymbolTracker {
return {
trackSymbol: noop,
moduleResolverHost: getModuleSpecifierResolverHost(context),
};
}
export interface TypeConstructionContext {
program: Program;
host: ModuleSpecifierResolutionHost;
}
/**
* @returns Empty string iff there we can't figure out a representation for `symbol` in `enclosingDeclaration`.
*/
function addNewNodeForMemberSymbol(symbol: Symbol, enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker, preferences: UserPreferences, out: (node: Node) => void): void {
function addNewNodeForMemberSymbol(symbol: Symbol, enclosingDeclaration: ClassLikeDeclaration, context: TypeConstructionContext, preferences: UserPreferences, out: (node: Node) => void): void {
const declarations = symbol.getDeclarations();
if (!(declarations && declarations.length)) {
return undefined;
}
const checker = context.program.getTypeChecker();
const declaration = declarations[0];
const name = getSynthesizedDeepClone(getNameOfDeclaration(declaration), /*includeTrivia*/ false) as PropertyName;
@ -36,7 +61,7 @@ namespace ts.codefix {
case SyntaxKind.SetAccessor:
case SyntaxKind.PropertySignature:
case SyntaxKind.PropertyDeclaration:
const typeNode = checker.typeToTypeNode(type, enclosingDeclaration);
const typeNode = checker.typeToTypeNode(type, enclosingDeclaration, /*flags*/ undefined, getNoopSymbolTrackerWithResolver(context));
out(createProperty(
/*decorators*/undefined,
modifiers,
@ -83,13 +108,13 @@ namespace ts.codefix {
}
function outputMethod(signature: Signature, modifiers: NodeArray<Modifier> | undefined, name: PropertyName, body?: Block): void {
const method = signatureToMethodDeclaration(checker, signature, enclosingDeclaration, modifiers, name, optional, body);
const method = signatureToMethodDeclaration(context, signature, enclosingDeclaration, modifiers, name, optional, body);
if (method) out(method);
}
}
function signatureToMethodDeclaration(
checker: TypeChecker,
context: TypeConstructionContext,
signature: Signature,
enclosingDeclaration: ClassLikeDeclaration,
modifiers: NodeArray<Modifier> | undefined,
@ -97,7 +122,8 @@ namespace ts.codefix {
optional: boolean,
body: Block | undefined,
): MethodDeclaration | undefined {
const signatureDeclaration = <MethodDeclaration>checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration, NodeBuilderFlags.NoTruncation | NodeBuilderFlags.SuppressAnyReturnType);
const program = context.program;
const signatureDeclaration = <MethodDeclaration>program.getTypeChecker().signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration, NodeBuilderFlags.NoTruncation | NodeBuilderFlags.SuppressAnyReturnType, getNoopSymbolTrackerWithResolver(context));
if (!signatureDeclaration) {
return undefined;
}
@ -117,18 +143,20 @@ namespace ts.codefix {
inJs: boolean,
makeStatic: boolean,
preferences: UserPreferences,
body: boolean,
contextNode: Node,
): MethodDeclaration {
const body = !isInterfaceDeclaration(contextNode);
const { typeArguments, arguments: args, parent } = call;
const checker = context.program.getTypeChecker();
const tracker = getNoopSymbolTrackerWithResolver(context);
const types = map(args, arg =>
// Widen the type so we don't emit nonsense annotations like "function fn(x: 3) {"
checker.typeToTypeNode(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(arg))));
checker.typeToTypeNode(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(arg)), contextNode, /*flags*/ undefined, tracker));
const names = map(args, arg =>
isIdentifier(arg) ? arg.text :
isPropertyAccessExpression(arg) ? arg.name.text : undefined);
const contextualType = checker.getContextualType(call);
const returnType = inJs ? undefined : contextualType && checker.typeToTypeNode(contextualType, call) || createKeywordTypeNode(SyntaxKind.AnyKeyword);
const returnType = inJs ? undefined : contextualType && checker.typeToTypeNode(contextualType, contextNode, /*flags*/ undefined, tracker) || createKeywordTypeNode(SyntaxKind.AnyKeyword);
return createMethod(
/*decorators*/ undefined,
/*modifiers*/ makeStatic ? [createToken(SyntaxKind.StaticKeyword)] : undefined,
@ -249,4 +277,46 @@ namespace ts.codefix {
}
return undefined;
}
export function setJsonCompilerOptionValue(
changeTracker: textChanges.ChangeTracker,
configFile: TsConfigSourceFile,
optionName: string,
optionValue: Expression,
) {
const tsconfigObjectLiteral = getTsConfigObjectLiteralExpression(configFile);
if (!tsconfigObjectLiteral) return undefined;
const compilerOptionsProperty = findJsonProperty(tsconfigObjectLiteral, "compilerOptions");
if (compilerOptionsProperty === undefined) {
changeTracker.insertNodeAtObjectStart(configFile, tsconfigObjectLiteral, createJsonPropertyAssignment(
"compilerOptions",
createObjectLiteral([
createJsonPropertyAssignment(optionName, optionValue),
])));
return;
}
const compilerOptions = compilerOptionsProperty.initializer;
if (!isObjectLiteralExpression(compilerOptions)) {
return;
}
const optionProperty = findJsonProperty(compilerOptions, optionName);
if (optionProperty === undefined) {
changeTracker.insertNodeAtObjectStart(configFile, compilerOptions, createJsonPropertyAssignment(optionName, optionValue));
}
else {
changeTracker.replaceNode(configFile, optionProperty.initializer, optionValue);
}
}
export function createJsonPropertyAssignment(name: string, initializer: Expression) {
return createPropertyAssignment(createStringLiteral(name), initializer);
}
export function findJsonProperty(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);
}
}

View file

@ -375,7 +375,7 @@ namespace ts.codefix {
const symbolName = isJsxOpeningLikeElement(symbolToken.parent)
&& symbolToken.parent.tagName === symbolToken
&& (isIntrinsicJsxName(symbolToken.text) || checker.resolveName(symbolToken.text, symbolToken, SymbolFlags.All, /*excludeGlobals*/ false))
? checker.getJsxNamespace()
? checker.getJsxNamespace(sourceFile)
: symbolToken.text;
// "default" is a keyword and not a legal identifier for the import, so we don't expect it here
Debug.assert(symbolName !== InternalSymbolName.Default);

View file

@ -104,7 +104,7 @@ namespace ts.Completions {
getJSCompletionEntries(sourceFile, location!.pos, uniqueNames, compilerOptions.target!, entries); // TODO: GH#18217
}
else {
if ((!symbols || symbols.length === 0) && keywordFilters === KeywordCompletionFilters.None) {
if (!isNewIdentifierLocation && (!symbols || symbols.length === 0) && keywordFilters === KeywordCompletionFilters.None) {
return undefined;
}
@ -367,7 +367,9 @@ namespace ts.Completions {
}
function getSymbolName(symbol: Symbol, origin: SymbolOriginInfo | undefined, target: ScriptTarget): string {
return origin && originIsExport(origin) && origin.isDefaultExport && symbol.escapedName === InternalSymbolName.Default
return origin && originIsExport(origin) && (
(origin.isDefaultExport && symbol.escapedName === InternalSymbolName.Default) ||
(symbol.escapedName === InternalSymbolName.ExportEquals))
// Name of "export default foo;" is "foo". Name of "export default 0" is the filename converted to camelCase.
? firstDefined(symbol.declarations, d => isExportAssignment(d) && isIdentifier(d.expression) ? d.expression.text : undefined)
|| codefix.moduleSymbolToValidIdentifier(origin.moduleSymbol, target)
@ -913,7 +915,7 @@ namespace ts.Completions {
}
else {
for (const symbol of type.getApparentProperties()) {
if (typeChecker.isValidPropertyAccessForCompletions(node.kind === SyntaxKind.ImportType ? <ImportTypeNode>node : <PropertyAccessExpression>node.parent, type, symbol)) {
if (typeChecker.isValidPropertyAccessForCompletions(node.kind === SyntaxKind.ImportType ? <ImportTypeNode>node : <PropertyAccessExpression | QualifiedName>node.parent, type, symbol)) {
addPropertySymbol(symbol);
}
}

View file

@ -151,7 +151,7 @@ namespace ts {
const toImport = oldFromNew !== undefined
// If we're at the new location (file was already renamed), need to redo module resolution starting from the old location.
// TODO:GH#18217
? getSourceFileToImportFromResolved(resolveModuleName(importLiteral.text, oldImportFromPath, program.getCompilerOptions(), host as ModuleResolutionHost), oldToNew, host)
? getSourceFileToImportFromResolved(resolveModuleName(importLiteral.text, oldImportFromPath, program.getCompilerOptions(), host as ModuleResolutionHost), oldToNew)
: getSourceFileToImport(importedModuleSymbol, importLiteral, sourceFile, program, host, oldToNew);
// Need an update if the imported file moved, or the importing file moved and was using a relative path.
@ -192,28 +192,35 @@ namespace ts {
const resolved = host.resolveModuleNames
? host.getResolvedModuleWithFailedLookupLocationsFromCache && host.getResolvedModuleWithFailedLookupLocationsFromCache(importLiteral.text, importingSourceFile.fileName)
: program.getResolvedModuleWithFailedLookupLocationsFromCache(importLiteral.text, importingSourceFile.fileName);
return getSourceFileToImportFromResolved(resolved, oldToNew, host);
return getSourceFileToImportFromResolved(resolved, oldToNew);
}
}
function getSourceFileToImportFromResolved(resolved: ResolvedModuleWithFailedLookupLocations | undefined, oldToNew: PathUpdater, host: LanguageServiceHost): ToImport | undefined {
function getSourceFileToImportFromResolved(resolved: ResolvedModuleWithFailedLookupLocations | undefined, oldToNew: PathUpdater): ToImport | undefined {
// Search through all locations looking for a moved file, and only then test already existing files.
// This is because if `a.ts` is compiled to `a.js` and `a.ts` is moved, we don't want to resolve anything to `a.js`, but to `a.ts`'s new location.
return tryEach(tryGetNewFile) || tryEach(tryGetOldFile);
if (!resolved) return undefined;
function tryEach(cb: (oldFileName: string) => ToImport | undefined): ToImport | undefined {
return resolved && (
(resolved.resolvedModule && cb(resolved.resolvedModule.resolvedFileName)) || firstDefined(resolved.failedLookupLocations, cb));
// First try resolved module
if (resolved.resolvedModule) {
const result = tryChange(resolved.resolvedModule.resolvedFileName);
if (result) return result;
}
function tryGetNewFile(oldFileName: string): ToImport | undefined {
const newFileName = oldToNew(oldFileName);
return newFileName !== undefined && host.fileExists!(newFileName) ? { newFileName, updated: true } : undefined; // TODO: GH#18217
// Then failed lookups except package.json since we dont want to touch them (only included ts/js files)
const result = forEach(resolved.failedLookupLocations, tryChangeWithIgnoringPackageJson);
if (result) return result;
// If nothing changed, then result is resolved module file thats not updated
return resolved.resolvedModule && { newFileName: resolved.resolvedModule.resolvedFileName, updated: false };
function tryChangeWithIgnoringPackageJson(oldFileName: string) {
return !endsWith(oldFileName, "/package.json") ? tryChange(oldFileName) : undefined;
}
function tryGetOldFile(oldFileName: string): ToImport | undefined {
function tryChange(oldFileName: string) {
const newFileName = oldToNew(oldFileName);
return host.fileExists!(oldFileName) ? newFileName !== undefined ? { newFileName, updated: true } : { newFileName: oldFileName, updated: false } : undefined; // TODO: GH#18217
return newFileName && { newFileName, updated: true };
}
}

View file

@ -660,7 +660,7 @@ namespace ts.NavigationBar {
else if (isCallExpression(parent)) {
const name = getCalledExpressionName(parent.expression);
if (name !== undefined) {
const args = mapDefined(parent.arguments, a => isStringLiteral(a) ? a.getText(curSourceFile) : undefined).join(", ");
const args = mapDefined(parent.arguments, a => isStringLiteralLike(a) ? a.getText(curSourceFile) : undefined).join(", ");
return `${name}(${args}) callback`;
}
}

View file

@ -28,12 +28,12 @@ namespace ts.OrganizeImports {
organizeImportsWorker(topLevelExportDecls, coalesceExports);
for (const ambientModule of sourceFile.statements.filter(isAmbientModule)) {
const ambientModuleBody = getModuleBlock(ambientModule as ModuleDeclaration)!; // TODO: GH#18217
if (!ambientModule.body) { continue; }
const ambientModuleImportDecls = ambientModuleBody.statements.filter(isImportDeclaration);
const ambientModuleImportDecls = ambientModule.body.statements.filter(isImportDeclaration);
organizeImportsWorker(ambientModuleImportDecls, coalesceAndOrganizeImports);
const ambientModuleExportDecls = ambientModuleBody.statements.filter(isExportDeclaration);
const ambientModuleExportDecls = ambientModule.body.statements.filter(isExportDeclaration);
organizeImportsWorker(ambientModuleExportDecls, coalesceExports);
}
@ -81,14 +81,9 @@ namespace ts.OrganizeImports {
}
}
function getModuleBlock(moduleDecl: ModuleDeclaration): ModuleBlock | undefined {
const body = moduleDecl.body;
return body && !isIdentifier(body) ? (isModuleBlock(body) ? body : getModuleBlock(body)) : undefined;
}
function removeUnusedImports(oldImports: ReadonlyArray<ImportDeclaration>, sourceFile: SourceFile, program: Program) {
const typeChecker = program.getTypeChecker();
const jsxNamespace = typeChecker.getJsxNamespace();
const jsxNamespace = typeChecker.getJsxNamespace(sourceFile);
const jsxElementsPresent = !!(sourceFile.transformFlags & TransformFlags.ContainsJsx);
const usedImports: ImportDeclaration[] = [];

View file

@ -37,6 +37,10 @@ namespace ts.OutliningElementsCollector {
addOutliningForLeadingCommentsForNode(n, sourceFile, cancellationToken, out);
}
if (isFunctionExpressionAssignedToVariable(n)) {
addOutliningForLeadingCommentsForNode(n.parent.parent.parent, sourceFile, cancellationToken, out);
}
const span = getOutliningSpanForNode(n, sourceFile);
if (span) out.push(span);
@ -54,6 +58,14 @@ namespace ts.OutliningElementsCollector {
}
depthRemaining++;
}
function isFunctionExpressionAssignedToVariable(n: Node) {
if (!isFunctionExpression(n) && !isArrowFunction(n)) {
return false;
}
const ancestor = findAncestor(n, isVariableStatement);
return !!ancestor && getSingleInitializerOfVariableStatementOrPropertyDeclaration(ancestor) === n;
}
}
function addRegionOutliningSpans(sourceFile: SourceFile, out: Push<OutliningSpan>): void {
@ -175,6 +187,7 @@ namespace ts.OutliningElementsCollector {
case SyntaxKind.ModuleBlock:
return spanForNode(n.parent);
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.EnumDeclaration:
case SyntaxKind.CaseBlock:
@ -206,10 +219,10 @@ namespace ts.OutliningElementsCollector {
}
function spanForObjectOrArrayLiteral(node: Node, open: SyntaxKind.OpenBraceToken | SyntaxKind.OpenBracketToken = SyntaxKind.OpenBraceToken): OutliningSpan | undefined {
// If the block has no leading keywords and is inside an array literal,
// If the block has no leading keywords and is inside an array literal or call expression,
// we only want to collapse the span of the block.
// Otherwise, the collapsed section will include the end of the previous line.
return spanForNode(node, /*autoCollapse*/ false, /*useFullStart*/ !isArrayLiteralExpression(node.parent), open);
return spanForNode(node, /*autoCollapse*/ false, /*useFullStart*/ !isArrayLiteralExpression(node.parent) && !isCallExpression(node.parent), open);
}
function spanForNode(hintSpanNode: Node, autoCollapse = false, useFullStart = true, open: SyntaxKind.OpenBraceToken | SyntaxKind.OpenBracketToken = SyntaxKind.OpenBraceToken): OutliningSpan | undefined {

View file

@ -1,14 +1,14 @@
/* @internal */
namespace ts.Rename {
export function getRenameInfo(program: Program, sourceFile: SourceFile, position: number): RenameInfo {
export function getRenameInfo(program: Program, sourceFile: SourceFile, position: number, options?: RenameInfoOptions): RenameInfo {
const node = getTouchingPropertyName(sourceFile, position);
const renameInfo = node && nodeIsEligibleForRename(node)
? getRenameInfoForNode(node, program.getTypeChecker(), sourceFile, declaration => program.isSourceFileDefaultLibrary(declaration.getSourceFile()))
? getRenameInfoForNode(node, program.getTypeChecker(), sourceFile, declaration => program.isSourceFileDefaultLibrary(declaration.getSourceFile()), options)
: undefined;
return renameInfo || getRenameInfoError(Diagnostics.You_cannot_rename_this_element);
}
function getRenameInfoForNode(node: Node, typeChecker: TypeChecker, sourceFile: SourceFile, isDefinedInLibraryFile: (declaration: Node) => boolean): RenameInfo | undefined {
function getRenameInfoForNode(node: Node, typeChecker: TypeChecker, sourceFile: SourceFile, isDefinedInLibraryFile: (declaration: Node) => boolean, options?: RenameInfoOptions): RenameInfo | undefined {
const symbol = typeChecker.getSymbolAtLocation(node);
if (!symbol) return;
// Only allow a symbol to be renamed if it actually has at least one declaration.
@ -26,7 +26,7 @@ namespace ts.Rename {
}
if (isStringLiteralLike(node) && tryGetImportFromModuleSpecifier(node)) {
return getRenameInfoForModule(node, sourceFile, symbol);
return options && options.allowRenameOfImportPath ? getRenameInfoForModule(node, sourceFile, symbol) : undefined;
}
const kind = SymbolDisplay.getSymbolKind(typeChecker, symbol, node);

View file

@ -2062,9 +2062,9 @@ namespace ts {
}
}
function getRenameInfo(fileName: string, position: number): RenameInfo {
function getRenameInfo(fileName: string, position: number, options?: RenameInfoOptions): RenameInfo {
synchronizeHostData();
return Rename.getRenameInfo(program, getValidSourceFile(fileName), position);
return Rename.getRenameInfo(program, getValidSourceFile(fileName), position, options);
}
function getRefactorContext(file: SourceFile, positionOrRange: number | TextRange, preferences: UserPreferences, formatOptions?: FormatCodeSettings): RefactorContext {

View file

@ -164,7 +164,7 @@ namespace ts {
* Returns a JSON-encoded value of the type:
* { canRename: boolean, localizedErrorMessage: string, displayName: string, fullDisplayName: string, kind: string, kindModifiers: string, triggerSpan: { start; length } }
*/
getRenameInfo(fileName: string, position: number): string;
getRenameInfo(fileName: string, position: number, options?: RenameInfoOptions): string;
/**
* Returns a JSON-encoded value of the type:
@ -831,10 +831,10 @@ namespace ts {
);
}
public getRenameInfo(fileName: string, position: number): string {
public getRenameInfo(fileName: string, position: number, options?: RenameInfoOptions): string {
return this.forwardJSONCall(
`getRenameInfo('${fileName}', ${position})`,
() => this.languageService.getRenameInfo(fileName, position)
() => this.languageService.getRenameInfo(fileName, position, options)
);
}

View file

@ -1,5 +1,7 @@
/* @internal */
namespace ts {
const visitedNestedConvertibleFunctions = createMap<true>();
export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): DiagnosticWithLocation[] {
program.getSemanticDiagnostics(sourceFile, cancellationToken);
const diags: DiagnosticWithLocation[] = [];
@ -13,6 +15,7 @@ namespace ts {
const isJsFile = isSourceFileJS(sourceFile);
visitedNestedConvertibleFunctions.clear();
check(sourceFile);
if (getAllowSyntheticDefaultImports(program.getCompilerOptions())) {
@ -114,17 +117,22 @@ namespace ts {
}
function addConvertToAsyncFunctionDiagnostics(node: FunctionLikeDeclaration, checker: TypeChecker, diags: Push<DiagnosticWithLocation>): void {
if (!isAsyncFunction(node) &&
node.body &&
isBlock(node.body) &&
hasReturnStatementWithPromiseHandler(node.body) &&
returnsPromise(node, checker)) {
// need to check function before checking map so that deeper levels of nested callbacks are checked
if (isConvertibleFunction(node, checker) && !visitedNestedConvertibleFunctions.has(getKeyFromNode(node))) {
diags.push(createDiagnosticForNode(
!node.name && isVariableDeclaration(node.parent) && isIdentifier(node.parent.name) ? node.parent.name : node,
Diagnostics.This_may_be_converted_to_an_async_function));
}
}
function isConvertibleFunction(node: FunctionLikeDeclaration, checker: TypeChecker) {
return !isAsyncFunction(node) &&
node.body &&
isBlock(node.body) &&
hasReturnStatementWithPromiseHandler(node.body) &&
returnsPromise(node, checker);
}
function returnsPromise(node: FunctionLikeDeclaration, checker: TypeChecker): boolean {
const functionType = checker.getTypeAtLocation(node);
const callSignatures = checker.getSignaturesOfType(functionType, SignatureKind.Call);
@ -169,14 +177,20 @@ namespace ts {
// should be kept up to date with getTransformationBody in convertToAsyncFunction.ts
function isFixablePromiseArgument(arg: Expression): boolean {
switch (arg.kind) {
case SyntaxKind.NullKeyword:
case SyntaxKind.Identifier: // identifier includes undefined
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
visitedNestedConvertibleFunctions.set(getKeyFromNode(arg as FunctionLikeDeclaration), true);
/* falls through */
case SyntaxKind.NullKeyword:
case SyntaxKind.Identifier: // identifier includes undefined
return true;
default:
return false;
}
}
function getKeyFromNode(exp: FunctionLikeDeclaration) {
return `${exp.pos.toString()}:${exp.end.toString()}`;
}
}

View file

@ -61,6 +61,7 @@
"codefixes/fixClassDoesntImplementInheritedAbstractMember.ts",
"codefixes/fixClassSuperMustPrecedeThisAccess.ts",
"codefixes/fixConstructorForDerivedNeedSuperCall.ts",
"codefixes/fixEnableExperimentalDecorators.ts",
"codefixes/fixExtendsInterfaceBecomesImplements.ts",
"codefixes/fixForgottenThisPropertyAccess.ts",
"codefixes/fixUnusedIdentifier.ts",

View file

@ -294,7 +294,7 @@ namespace ts {
getSignatureHelpItems(fileName: string, position: number, options: SignatureHelpItemsOptions | undefined): SignatureHelpItems | undefined;
getRenameInfo(fileName: string, position: number): RenameInfo;
getRenameInfo(fileName: string, position: number, options?: RenameInfoOptions): RenameInfo;
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ReadonlyArray<RenameLocation> | undefined;
getDefinitionAtPosition(fileName: string, position: number): ReadonlyArray<DefinitionInfo> | undefined;
@ -848,6 +848,10 @@ namespace ts {
localizedErrorMessage: string;
}
export interface RenameInfoOptions {
readonly allowRenameOfImportPath?: boolean;
}
export interface SignatureHelpParameter {
name: string;
documentation: SymbolDisplayPart[];

View file

@ -89,6 +89,7 @@
"unittests/services/transpile.ts",
"unittests/tscWatch/consoleClearing.ts",
"unittests/tscWatch/emit.ts",
"unittests/tscWatch/emitAndErrorUpdates.ts",
"unittests/tscWatch/programUpdates.ts",
"unittests/tscWatch/resolutionCache.ts",
"unittests/tscWatch/watchEnvironment.ts",

View file

@ -95,6 +95,39 @@ namespace ts {
module: ModuleKind.ES2015,
emitDecoratorMetadata: true,
experimentalDecorators: true
});
});
emitsCorrectly("sourceMapExternalSourceFiles",
[
{
file: "source.ts",
// The text of length 'changed' is made to be on two lines so we know the line map change
text: `\`multi
line\`
'change'`
},
],
{
before: [
context => node => visitNode(node, function visitor(node: Node): Node {
if (isStringLiteral(node) && node.text === "change") {
const text = "'changed'";
const lineMap = computeLineStarts(text);
setSourceMapRange(node, {
pos: 0, end: text.length, source: {
text,
fileName: "another.html",
lineMap,
getLineAndCharacterOfPosition: pos => computeLineAndCharacterOfPosition(lineMap, pos)
}
});
return node;
}
return visitEachChild(node, visitor, context);
})
]
},
{ sourceMap: true }
);
});
}

View file

@ -255,7 +255,7 @@ interface String { charAt: any; }
interface Array<T> {}`
};
function testConvertToAsyncFunction(caption: string, text: string, baselineFolder: string, includeLib?: boolean, expectFailure = false) {
function testConvertToAsyncFunction(caption: string, text: string, baselineFolder: string, includeLib?: boolean, expectFailure = false, onlyProvideAction = false) {
const t = extractTest(text);
const selectionRange = t.ranges.get("selection")!;
if (!selectionRange) {
@ -307,7 +307,7 @@ interface Array<T> {}`
const actions = codefix.getFixes(context);
const action = find(actions, action => action.description === Diagnostics.Convert_to_async_function.message);
if (expectFailure) {
if (expectFailure && !onlyProvideAction) {
assert.isNotTrue(action && action.changes.length > 0);
return;
}
@ -1151,25 +1151,25 @@ function [#|f|]() {
_testConvertToAsyncFunction("convertToAsyncFunction_simpleFunctionExpression", `
const [#|foo|] = function () {
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
}
}
`);
_testConvertToAsyncFunction("convertToAsyncFunction_simpleFunctionExpressionWithName", `
const foo = function [#|f|]() {
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
}
}
`);
_testConvertToAsyncFunction("convertToAsyncFunction_simpleFunctionExpressionAssignedToBindingPattern", `
const { length } = [#|function|] () {
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
}
}
`);
_testConvertToAsyncFunction("convertToAsyncFunction_catchBlockUniqueParams", `
function [#|f|]() {
return Promise.resolve().then(x => 1).catch(x => "a").then(x => !!x);
}
return Promise.resolve().then(x => 1).catch(x => "a").then(x => !!x);
}
`);
_testConvertToAsyncFunction("convertToAsyncFunction_bindingPattern", `
@ -1178,7 +1178,7 @@ function [#|f|]() {
}
function res({ status, trailer }){
console.log(status);
}
}
`);
_testConvertToAsyncFunction("convertToAsyncFunction_bindingPatternNameCollision", `
@ -1188,7 +1188,7 @@ function [#|f|]() {
}
function res({ status, trailer }){
console.log(status);
}
}
`);
_testConvertToAsyncFunctionFailed("convertToAsyncFunction_thenArgumentNotFunction", `
@ -1209,7 +1209,7 @@ function [#|f|]() {
}
function res(result) {
return Promise.resolve().then(x => console.log(result));
}
}
`);
_testConvertToAsyncFunction("convertToAsyncFunction_callbackReturnsPromise", `
@ -1241,7 +1241,7 @@ function [#|f|]() {
return Promise.resolve(1)
.then(x => Promise.reject(x))
.catch(err => console.log(err));
}
}
`);
_testConvertToAsyncFunction("convertToAsyncFunction_nestedPromises", `
@ -1266,6 +1266,22 @@ _testConvertToAsyncFunction("convertToAsyncFunction_exportModifier", `
export function [#|foo|]() {
return fetch('https://typescriptlang.org').then(s => console.log(s));
}
`);
_testConvertToAsyncFunction("convertToAsyncFunction_OutermostOnlySuccess", `
function [#|foo|]() {
return fetch('a').then(() => {
return fetch('b').then(() => 'c');
})
}
`);
_testConvertToAsyncFunctionFailedSuggestion("convertToAsyncFunction_OutermostOnlyFailure", `
function foo() {
return fetch('a').then([#|() => {|]
return fetch('b').then(() => 'c');
})
}
`);
});
@ -1276,4 +1292,8 @@ export function [#|foo|]() {
function _testConvertToAsyncFunctionFailed(caption: string, text: string) {
testConvertToAsyncFunction(caption, text, "convertToAsyncFunction", /*includeLib*/ true, /*expectFailure*/ true);
}
function _testConvertToAsyncFunctionFailedSuggestion(caption: string, text: string) {
testConvertToAsyncFunction(caption, text, "convertToAsyncFunction", /*includeLib*/ true, /*expectFailure*/ true, /*onlyProvideAction*/ true);
}
}

View file

@ -274,6 +274,16 @@ export const Other = 1;
assert.isEmpty(changes);
});
it("doesn't crash on shorthand ambient module", () => {
const testFile = {
path: "/a.ts",
content: "declare module '*';",
};
const languageService = makeLanguageService(testFile);
const changes = languageService.organizeImports({ type: "file", fileName: testFile.path }, testFormatSettings, emptyOptions);
assert.isEmpty(changes);
});
testOrganizeImports("Renamed_used",
{
path: "/test.ts",
@ -586,6 +596,34 @@ import { React, Other } from "react";
},
reactLibFile);
testOrganizeImports("JsxPragmaTsx",
{
path: "/test.tsx",
content: `/** @jsx jsx */
import { Global, jsx } from '@emotion/core';
import * as React from 'react';
export const App: React.FunctionComponent = _ => <Global><h1>Hello!</h1></Global>
`,
},
{
path: "/@emotion/core/index.d.ts",
content: `import { createElement } from 'react'
export const jsx: typeof createElement;
export function Global(props: any): ReactElement<any>;`
},
{
path: reactLibFile.path,
content: `${reactLibFile.content}
export namespace React {
interface FunctionComponent {
}
}
`
}
);
describe("Exports", () => {
testOrganizeExports("MoveToTop",

View file

@ -479,7 +479,7 @@ let x: string = 10;`);
const { host, solutionBuilder } = createSolutionOfProject(allFiles, currentDirectory, solutionBuilderconfig, getOutputFileStamps);
// Build in watch mode
const watch = createWatchOfConfigFileReturningBuilder(watchConfig, host);
const watch = createWatchOfConfigFile(watchConfig, host);
checkOutputErrorsInitial(host, emptyArray);
return { host, solutionBuilder, watch };
@ -505,10 +505,8 @@ let x: string = 10;`);
projectSystem.checkProjectActualFiles(service.configuredProjects.get(configFile.toLowerCase())!, expectedFiles);
}
type Watch = () => BuilderProgram;
function verifyDependencies(watch: Watch, filePath: string, expected: ReadonlyArray<string>) {
checkArray(`${filePath} dependencies`, watch().getAllDependencies(watch().getSourceFile(filePath)!), expected);
checkArray(`${filePath} dependencies`, watch.getBuilderProgram().getAllDependencies(watch().getSourceFile(filePath)!), expected);
}
describe("on sample project", () => {
@ -542,7 +540,7 @@ let x: string = 10;`);
host.checkTimeoutQueueLengthAndRun(1);
checkOutputErrorsIncremental(host, emptyArray);
checkProgramActualFiles(watch().getProgram(), expectedFilesAfterEdit);
checkProgramActualFiles(watch(), expectedFilesAfterEdit);
});
@ -642,7 +640,7 @@ export function gfoo() {
expectedWatchedDirectoriesRecursive: ReadonlyArray<string>,
dependencies: ReadonlyArray<[string, ReadonlyArray<string>]>,
expectedWatchedDirectories?: ReadonlyArray<string>) {
checkProgramActualFiles(watch().getProgram(), expectedProgramFiles);
checkProgramActualFiles(watch(), expectedProgramFiles);
verifyWatchesOfProject(host, expectedWatchedFiles, expectedWatchedDirectoriesRecursive, expectedWatchedDirectories);
for (const [file, deps] of dependencies) {
verifyDependencies(watch, file, deps);

View file

@ -0,0 +1,307 @@
namespace ts.tscWatch {
describe("unittests:: tsc-watch:: Emit times and Error updates in builder after program changes", () => {
const currentDirectory = "/user/username/projects/myproject";
const config: File = {
path: `${currentDirectory}/tsconfig.json`,
content: `{}`
};
function getOutputFileStampAndError(host: WatchedSystem, watch: Watch, file: File) {
const builderProgram = watch.getBuilderProgram();
const state = builderProgram.getState();
return {
file,
fileStamp: host.getModifiedTime(file.path.replace(".ts", ".js")),
errors: builderProgram.getSemanticDiagnostics(watch().getSourceFileByPath(file.path as Path)),
errorsFromOldState: !!state.semanticDiagnosticsFromOldState && state.semanticDiagnosticsFromOldState.has(file.path)
};
}
function getOutputFileStampsAndErrors(host: WatchedSystem, watch: Watch, directoryFiles: ReadonlyArray<File>) {
return directoryFiles.map(d => getOutputFileStampAndError(host, watch, d));
}
function findStampAndErrors(stampsAndErrors: ReadonlyArray<ReturnType<typeof getOutputFileStampAndError>>, file: File) {
return find(stampsAndErrors, info => info.file === file)!;
}
function verifyOutputFileStampsAndErrors(
file: File,
emitExpected: boolean,
errorRefershExpected: boolean,
beforeChangeFileStampsAndErrors: ReadonlyArray<ReturnType<typeof getOutputFileStampAndError>>,
afterChangeFileStampsAndErrors: ReadonlyArray<ReturnType<typeof getOutputFileStampAndError>>
) {
const beforeChange = findStampAndErrors(beforeChangeFileStampsAndErrors, file);
const afterChange = findStampAndErrors(afterChangeFileStampsAndErrors, file);
if (emitExpected) {
assert.notStrictEqual(afterChange.fileStamp, beforeChange.fileStamp, `Expected emit for file ${file.path}`);
}
else {
assert.strictEqual(afterChange.fileStamp, beforeChange.fileStamp, `Did not expect new emit for file ${file.path}`);
}
if (errorRefershExpected) {
if (afterChange.errors !== emptyArray || beforeChange.errors !== emptyArray) {
assert.notStrictEqual(afterChange.errors, beforeChange.errors, `Expected new errors for file ${file.path}`);
}
assert.isFalse(afterChange.errorsFromOldState, `Expected errors to be not copied from old state for file ${file.path}`);
}
else {
assert.strictEqual(afterChange.errors, beforeChange.errors, `Expected errors to not change for file ${file.path}`);
assert.isTrue(afterChange.errorsFromOldState, `Expected errors to be copied from old state for file ${file.path}`);
}
}
interface VerifyEmitAndErrorUpdates {
change: (host: WatchedSystem) => void;
getInitialErrors: (watch: Watch) => ReadonlyArray<Diagnostic> | ReadonlyArray<string>;
getIncrementalErrors: (watch: Watch) => ReadonlyArray<Diagnostic> | ReadonlyArray<string>;
filesWithNewEmit: ReadonlyArray<File>;
filesWithOnlyErrorRefresh: ReadonlyArray<File>;
filesNotTouched: ReadonlyArray<File>;
configFile?: File;
}
function verifyEmitAndErrorUpdates({ filesWithNewEmit, filesWithOnlyErrorRefresh, filesNotTouched, configFile = config, change, getInitialErrors, getIncrementalErrors }: VerifyEmitAndErrorUpdates) {
const nonLibFiles = [...filesWithNewEmit, ...filesWithOnlyErrorRefresh, ...filesNotTouched];
const files = [...nonLibFiles, configFile, libFile];
const host = createWatchedSystem(files, { currentDirectory });
const watch = createWatchOfConfigFile("tsconfig.json", host);
checkProgramActualFiles(watch(), [...nonLibFiles.map(f => f.path), libFile.path]);
checkOutputErrorsInitial(host, getInitialErrors(watch));
const beforeChange = getOutputFileStampsAndErrors(host, watch, nonLibFiles);
change(host);
host.runQueuedTimeoutCallbacks();
checkOutputErrorsIncremental(host, getIncrementalErrors(watch));
const afterChange = getOutputFileStampsAndErrors(host, watch, nonLibFiles);
filesWithNewEmit.forEach(file => verifyOutputFileStampsAndErrors(file, /*emitExpected*/ true, /*errorRefershExpected*/ true, beforeChange, afterChange));
filesWithOnlyErrorRefresh.forEach(file => verifyOutputFileStampsAndErrors(file, /*emitExpected*/ false, /*errorRefershExpected*/ true, beforeChange, afterChange));
filesNotTouched.forEach(file => verifyOutputFileStampsAndErrors(file, /*emitExpected*/ false, /*errorRefershExpected*/ false, beforeChange, afterChange));
}
describe("deep import changes", () => {
const aFile: File = {
path: `${currentDirectory}/a.ts`,
content: `import {B} from './b';
declare var console: any;
let b = new B();
console.log(b.c.d);`
};
function verifyDeepImportChange(bFile: File, cFile: File) {
const filesWithNewEmit: File[] = [];
const filesWithOnlyErrorRefresh = [aFile];
addImportedModule(bFile);
addImportedModule(cFile);
verifyEmitAndErrorUpdates({
filesWithNewEmit,
filesWithOnlyErrorRefresh,
filesNotTouched: emptyArray,
change: host => host.writeFile(cFile.path, cFile.content.replace("d", "d2")),
getInitialErrors: () => emptyArray,
getIncrementalErrors: watch => [
getDiagnosticOfFileFromProgram(watch(), aFile.path, aFile.content.lastIndexOf("d"), 1, Diagnostics.Property_0_does_not_exist_on_type_1, "d", "C")
]
});
function addImportedModule(file: File) {
if (file.path.endsWith(".d.ts")) {
filesWithOnlyErrorRefresh.push(file);
}
else {
filesWithNewEmit.push(file);
}
}
}
it("updates errors when deep import file changes", () => {
const bFile: File = {
path: `${currentDirectory}/b.ts`,
content: `import {C} from './c';
export class B
{
c = new C();
}`
};
const cFile: File = {
path: `${currentDirectory}/c.ts`,
content: `export class C
{
d = 1;
}`
};
verifyDeepImportChange(bFile, cFile);
});
it("updates errors when deep import through declaration file changes", () => {
const bFile: File = {
path: `${currentDirectory}/b.d.ts`,
content: `import {C} from './c';
export class B
{
c: C;
}`
};
const cFile: File = {
path: `${currentDirectory}/c.d.ts`,
content: `export class C
{
d: number;
}`
};
verifyDeepImportChange(bFile, cFile);
});
});
it("updates errors in file not exporting a deep multilevel import that changes", () => {
const aFile: File = {
path: `${currentDirectory}/a.ts`,
content: `export interface Point {
name: string;
c: Coords;
}
export interface Coords {
x2: number;
y: number;
}`
};
const bFile: File = {
path: `${currentDirectory}/b.ts`,
content: `import { Point } from "./a";
export interface PointWrapper extends Point {
}`
};
const cFile: File = {
path: `${currentDirectory}/c.ts`,
content: `import { PointWrapper } from "./b";
export function getPoint(): PointWrapper {
return {
name: "test",
c: {
x: 1,
y: 2
}
}
};`
};
const dFile: File = {
path: `${currentDirectory}/d.ts`,
content: `import { getPoint } from "./c";
getPoint().c.x;`
};
const eFile: File = {
path: `${currentDirectory}/e.ts`,
content: `import "./d";`
};
verifyEmitAndErrorUpdates({
filesWithNewEmit: [aFile, bFile],
filesWithOnlyErrorRefresh: [cFile, dFile],
filesNotTouched: [eFile],
change: host => host.writeFile(aFile.path, aFile.content.replace("x2", "x")),
getInitialErrors: watch => [
getDiagnosticOfFileFromProgram(watch(), cFile.path, cFile.content.indexOf("x: 1"), 4, chainDiagnosticMessages(
chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Object_literal_may_only_specify_known_properties_and_0_does_not_exist_in_type_1, "x", "Coords"),
Diagnostics.Type_0_is_not_assignable_to_type_1,
"{ x: number; y: number; }",
"Coords"
)),
getDiagnosticOfFileFromProgram(watch(), dFile.path, dFile.content.lastIndexOf("x"), 1, Diagnostics.Property_0_does_not_exist_on_type_1, "x", "Coords")
],
getIncrementalErrors: () => emptyArray
});
});
describe("updates errors when file transitively exported file changes", () => {
const config: File = {
path: `${currentDirectory}/tsconfig.json`,
content: JSON.stringify({
files: ["app.ts"],
compilerOptions: { baseUrl: "." }
})
};
const app: File = {
path: `${currentDirectory}/app.ts`,
content: `import { Data } from "lib2/public";
export class App {
public constructor() {
new Data().test();
}
}`
};
const lib2Public: File = {
path: `${currentDirectory}/lib2/public.ts`,
content: `export * from "./data";`
};
const lib2Data: File = {
path: `${currentDirectory}/lib2/data.ts`,
content: `import { ITest } from "lib1/public";
export class Data {
public test() {
const result: ITest = {
title: "title"
}
return result;
}
}`
};
const lib1Public: File = {
path: `${currentDirectory}/lib1/public.ts`,
content: `export * from "./tools/public";`
};
const lib1ToolsPublic: File = {
path: `${currentDirectory}/lib1/tools/public.ts`,
content: `export * from "./tools.interface";`
};
const lib1ToolsInterface: File = {
path: `${currentDirectory}/lib1/tools/tools.interface.ts`,
content: `export interface ITest {
title: string;
}`
};
function verifyTransitiveExports(lib2Data: File, lib2Data2?: File) {
const filesWithNewEmit = [lib1ToolsInterface, lib1ToolsPublic];
const filesWithOnlyErrorRefresh = [app, lib2Public, lib1Public, lib2Data];
if (lib2Data2) {
filesWithOnlyErrorRefresh.push(lib2Data2);
}
verifyEmitAndErrorUpdates({
filesWithNewEmit,
filesWithOnlyErrorRefresh,
filesNotTouched: emptyArray,
configFile: config,
change: host => host.writeFile(lib1ToolsInterface.path, lib1ToolsInterface.content.replace("title", "title2")),
getInitialErrors: () => emptyArray,
getIncrementalErrors: () => [
"lib2/data.ts(5,13): error TS2322: Type '{ title: string; }' is not assignable to type 'ITest'.\n Object literal may only specify known properties, but 'title' does not exist in type 'ITest'. Did you mean to write 'title2'?\n"
]
});
}
it("when there are no circular import and exports", () => {
verifyTransitiveExports(lib2Data);
});
it("when there are circular import and exports", () => {
const lib2Data: File = {
path: `${currentDirectory}/lib2/data.ts`,
content: `import { ITest } from "lib1/public"; import { Data2 } from "./data2";
export class Data {
public dat?: Data2; public test() {
const result: ITest = {
title: "title"
}
return result;
}
}`
};
const lib2Data2: File = {
path: `${currentDirectory}/lib2/data2.ts`,
content: `import { Data } from "./data";
export class Data2 {
public dat?: Data;
}`
};
verifyTransitiveExports(lib2Data, lib2Data2);
});
});
});
}

View file

@ -29,18 +29,18 @@ 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 interface Watch {
(): Program;
getBuilderProgram(): EmitAndSemanticDiagnosticsBuilderProgram;
}
export function createWatchOfConfigFile(configFileName: string, host: WatchedSystem, maxNumberOfFilesToIterateForInvalidation?: number) {
const compilerHost = createWatchCompilerHostOfConfigFile(configFileName, {}, host);
compilerHost.maxNumberOfFilesToIterateForInvalidation = maxNumberOfFilesToIterateForInvalidation;
const watch = createWatchProgram(compilerHost);
return () => watch.getCurrentProgram().getProgram();
const result = (() => watch.getCurrentProgram().getProgram()) as Watch;
result.getBuilderProgram = () => watch.getCurrentProgram();
return result;
}
export function createWatchOfFilesAndCompilerOptions(rootFiles: string[], host: WatchedSystem, options: CompilerOptions = {}, maxNumberOfFilesToIterateForInvalidation?: number) {
@ -152,7 +152,21 @@ namespace ts.tscWatch {
assert.equal(host.exitCode, expectedExitCode);
}
export function getDiagnosticOfFileFrom(file: SourceFile | undefined, text: string, start: number | undefined, length: number | undefined, message: DiagnosticMessage): Diagnostic {
function isDiagnosticMessageChain(message: DiagnosticMessage | DiagnosticMessageChain): message is DiagnosticMessageChain {
return !!(message as DiagnosticMessageChain).messageText;
}
export function getDiagnosticOfFileFrom(file: SourceFile | undefined, start: number | undefined, length: number | undefined, message: DiagnosticMessage | DiagnosticMessageChain, ..._args: (string | number)[]): Diagnostic {
let text: DiagnosticMessageChain | string;
if (isDiagnosticMessageChain(message)) {
text = message;
}
else {
text = getLocaleSpecificMessage(message);
if (arguments.length > 4) {
text = formatStringFromArgs(text, arguments, 4);
}
}
return {
file,
start,
@ -164,35 +178,17 @@ namespace ts.tscWatch {
};
}
export function getDiagnosticWithoutFile(message: DiagnosticMessage, ..._args: (string | number)[]): Diagnostic {
let text = getLocaleSpecificMessage(message);
if (arguments.length > 1) {
text = formatStringFromArgs(text, arguments, 1);
}
return getDiagnosticOfFileFrom(/*file*/ undefined, text, /*start*/ undefined, /*length*/ undefined, message);
export function getDiagnosticWithoutFile(message: DiagnosticMessage | DiagnosticMessageChain, ...args: (string | number)[]): Diagnostic {
return getDiagnosticOfFileFrom(/*file*/ undefined, /*start*/ undefined, /*length*/ undefined, message, ...args);
}
export function getDiagnosticOfFile(file: SourceFile, start: number, length: number, message: DiagnosticMessage, ..._args: (string | number)[]): Diagnostic {
let text = getLocaleSpecificMessage(message);
if (arguments.length > 4) {
text = formatStringFromArgs(text, arguments, 4);
}
return getDiagnosticOfFileFrom(file, text, start, length, message);
export function getDiagnosticOfFile(file: SourceFile, start: number, length: number, message: DiagnosticMessage | DiagnosticMessageChain, ...args: (string | number)[]): Diagnostic {
return getDiagnosticOfFileFrom(file, start, length, message, ...args);
}
export function getDiagnosticOfFileFromProgram(program: Program, filePath: string, start: number, length: number, message: DiagnosticMessage, ..._args: (string | number)[]): Diagnostic {
let text = getLocaleSpecificMessage(message);
if (arguments.length > 5) {
text = formatStringFromArgs(text, arguments, 5);
}
export function getDiagnosticOfFileFromProgram(program: Program, filePath: string, start: number, length: number, message: DiagnosticMessage | DiagnosticMessageChain, ...args: (string | number)[]): Diagnostic {
return getDiagnosticOfFileFrom(program.getSourceFileByPath(toPath(filePath, program.getCurrentDirectory(), s => s.toLowerCase()))!,
text, start, length, message);
start, length, message, ...args);
}
export function getUnknownCompilerOption(program: Program, configFile: File, option: string) {

View file

@ -1070,92 +1070,6 @@ export default test;`;
}
});
it("updates errors when deep import file changes", () => {
const currentDirectory = "/user/username/projects/myproject";
const aFile: File = {
path: `${currentDirectory}/a.ts`,
content: `import {B} from './b';
declare var console: any;
let b = new B();
console.log(b.c.d);`
};
const bFile: File = {
path: `${currentDirectory}/b.ts`,
content: `import {C} from './c';
export class B
{
c = new C();
}`
};
const cFile: File = {
path: `${currentDirectory}/c.ts`,
content: `export class C
{
d = 1;
}`
};
const config: File = {
path: `${currentDirectory}/tsconfig.json`,
content: `{}`
};
const files = [aFile, bFile, cFile, config, libFile];
const host = createWatchedSystem(files, { currentDirectory });
const watch = createWatchOfConfigFile("tsconfig.json", host);
checkProgramActualFiles(watch(), [aFile.path, bFile.path, cFile.path, libFile.path]);
checkOutputErrorsInitial(host, emptyArray);
const modifiedTimeOfAJs = host.getModifiedTime(`${currentDirectory}/a.js`);
host.writeFile(cFile.path, cFile.content.replace("d", "d2"));
host.runQueuedTimeoutCallbacks();
checkOutputErrorsIncremental(host, [
getDiagnosticOfFileFromProgram(watch(), aFile.path, aFile.content.lastIndexOf("d"), 1, Diagnostics.Property_0_does_not_exist_on_type_1, "d", "C")
]);
// File a need not be rewritten
assert.equal(host.getModifiedTime(`${currentDirectory}/a.js`), modifiedTimeOfAJs);
});
it("updates errors when deep import through declaration file changes", () => {
const currentDirectory = "/user/username/projects/myproject";
const aFile: File = {
path: `${currentDirectory}/a.ts`,
content: `import {B} from './b';
declare var console: any;
let b = new B();
console.log(b.c.d);`
};
const bFile: File = {
path: `${currentDirectory}/b.d.ts`,
content: `import {C} from './c';
export class B
{
c: C;
}`
};
const cFile: File = {
path: `${currentDirectory}/c.d.ts`,
content: `export class C
{
d: number;
}`
};
const config: File = {
path: `${currentDirectory}/tsconfig.json`,
content: `{}`
};
const files = [aFile, bFile, cFile, config, libFile];
const host = createWatchedSystem(files, { currentDirectory });
const watch = createWatchOfConfigFile("tsconfig.json", host);
checkProgramActualFiles(watch(), [aFile.path, bFile.path, cFile.path, libFile.path]);
checkOutputErrorsInitial(host, emptyArray);
const modifiedTimeOfAJs = host.getModifiedTime(`${currentDirectory}/a.js`);
host.writeFile(cFile.path, cFile.content.replace("d", "d2"));
host.runQueuedTimeoutCallbacks();
checkOutputErrorsIncremental(host, [
getDiagnosticOfFileFromProgram(watch(), aFile.path, aFile.content.lastIndexOf("d"), 1, Diagnostics.Property_0_does_not_exist_on_type_1, "d", "C")
]);
// File a need not be rewritten
assert.equal(host.getModifiedTime(`${currentDirectory}/a.js`), modifiedTimeOfAJs);
});
it("updates errors when strictNullChecks changes", () => {
const currentDirectory = "/user/username/projects/myproject";
const aFile: File = {
@ -1228,98 +1142,6 @@ foo().hello`
checkOutputErrorsIncremental(host, emptyArray);
});
describe("updates errors when file transitively exported file changes", () => {
const projectLocation = "/user/username/projects/myproject";
const config: File = {
path: `${projectLocation}/tsconfig.json`,
content: JSON.stringify({
files: ["app.ts"],
compilerOptions: { baseUrl: "." }
})
};
const app: File = {
path: `${projectLocation}/app.ts`,
content: `import { Data } from "lib2/public";
export class App {
public constructor() {
new Data().test();
}
}`
};
const lib2Public: File = {
path: `${projectLocation}/lib2/public.ts`,
content: `export * from "./data";`
};
const lib2Data: File = {
path: `${projectLocation}/lib2/data.ts`,
content: `import { ITest } from "lib1/public";
export class Data {
public test() {
const result: ITest = {
title: "title"
}
return result;
}
}`
};
const lib1Public: File = {
path: `${projectLocation}/lib1/public.ts`,
content: `export * from "./tools/public";`
};
const lib1ToolsPublic: File = {
path: `${projectLocation}/lib1/tools/public.ts`,
content: `export * from "./tools.interface";`
};
const lib1ToolsInterface: File = {
path: `${projectLocation}/lib1/tools/tools.interface.ts`,
content: `export interface ITest {
title: string;
}`
};
function verifyTransitiveExports(filesWithoutConfig: ReadonlyArray<File>) {
const files = [config, ...filesWithoutConfig];
const host = createWatchedSystem(files, { currentDirectory: projectLocation });
const watch = createWatchOfConfigFile(config.path, host);
checkProgramActualFiles(watch(), filesWithoutConfig.map(f => f.path));
checkOutputErrorsInitial(host, emptyArray);
host.writeFile(lib1ToolsInterface.path, lib1ToolsInterface.content.replace("title", "title2"));
host.checkTimeoutQueueLengthAndRun(1);
checkProgramActualFiles(watch(), filesWithoutConfig.map(f => f.path));
checkOutputErrorsIncremental(host, [
"lib2/data.ts(5,13): error TS2322: Type '{ title: string; }' is not assignable to type 'ITest'.\n Object literal may only specify known properties, but 'title' does not exist in type 'ITest'. Did you mean to write 'title2'?\n"
]);
}
it("when there are no circular import and exports", () => {
verifyTransitiveExports([libFile, app, lib2Public, lib2Data, lib1Public, lib1ToolsPublic, lib1ToolsInterface]);
});
it("when there are circular import and exports", () => {
const lib2Data: File = {
path: `${projectLocation}/lib2/data.ts`,
content: `import { ITest } from "lib1/public"; import { Data2 } from "./data2";
export class Data {
public dat?: Data2; public test() {
const result: ITest = {
title: "title"
}
return result;
}
}`
};
const lib2Data2: File = {
path: `${projectLocation}/lib2/data2.ts`,
content: `import { Data } from "./data";
export class Data2 {
public dat?: Data;
}`
};
verifyTransitiveExports([libFile, app, lib2Public, lib2Data, lib2Data2, lib1Public, lib1ToolsPublic, lib1ToolsInterface]);
});
});
describe("updates errors in lib file", () => {
const currentDirectory = "/user/username/projects/myproject";
const field = "fullscreen";
@ -1459,7 +1281,59 @@ interface Document {
checkProgramActualFiles(watch(), [aFile.path, bFile.path, libFile.path]);
}
});
it("reports errors correctly with isolatedModules", () => {
const currentDirectory = "/user/username/projects/myproject";
const aFile: File = {
path: `${currentDirectory}/a.ts`,
content: `export const a: string = "";`
};
const bFile: File = {
path: `${currentDirectory}/b.ts`,
content: `import { a } from "./a";
const b: string = a;`
};
const configFile: File = {
path: `${currentDirectory}/tsconfig.json`,
content: JSON.stringify({
compilerOptions: {
isolatedModules: true
}
})
};
const files = [aFile, bFile, libFile, configFile];
const host = createWatchedSystem(files, { currentDirectory });
const watch = createWatchOfConfigFile("tsconfig.json", host);
verifyProgramFiles();
checkOutputErrorsInitial(host, emptyArray);
assert.equal(host.readFile(`${currentDirectory}/a.js`), `"use strict";
exports.__esModule = true;
exports.a = "";
`, "Contents of a.js");
assert.equal(host.readFile(`${currentDirectory}/b.js`), `"use strict";
exports.__esModule = true;
var a_1 = require("./a");
var b = a_1.a;
`, "Contents of b.js");
const modifiedTime = host.getModifiedTime(`${currentDirectory}/b.js`);
host.writeFile(aFile.path, `export const a: number = 1`);
host.runQueuedTimeoutCallbacks();
verifyProgramFiles();
checkOutputErrorsIncremental(host, [
getDiagnosticOfFileFromProgram(watch(), bFile.path, bFile.content.indexOf("b"), 1, Diagnostics.Type_0_is_not_assignable_to_type_1, "number", "string")
]);
assert.equal(host.readFile(`${currentDirectory}/a.js`), `"use strict";
exports.__esModule = true;
exports.a = 1;
`, "Contents of a.js");
assert.equal(host.getModifiedTime(`${currentDirectory}/b.js`), modifiedTime, "Timestamp of b.js");
function verifyProgramFiles() {
checkProgramActualFiles(watch(), [aFile.path, bFile.path, libFile.path]);
}
});
});
}

View file

@ -760,5 +760,63 @@ namespace ts.projectSystem {
assert.equal(project2.pendingReload, ConfigFileProgramReloadLevel.None); // External project referenced configured project loaded
checkProjectActualFiles(project2, [config.path, f1.path]);
});
it("handles creation of external project with jsconfig before jsconfig creation watcher is invoked", () => {
const projectLocation = `/user/username/projects/WebApplication36/WebApplication36`;
const projectFileName = `${projectLocation}/WebApplication36.csproj`;
const tsconfig: File = {
path: `${projectLocation}/tsconfig.json`,
content: "{}"
};
const files = [libFile, tsconfig];
const host = createServerHost(files);
const service = createProjectService(host);
// Create external project
service.openExternalProjects([{
projectFileName,
rootFiles: [{ fileName: tsconfig.path }],
options: { allowJs: false }
}]);
checkNumberOfProjects(service, { configuredProjects: 1 });
const configProject = service.configuredProjects.get(tsconfig.path.toLowerCase())!;
checkProjectActualFiles(configProject, [tsconfig.path]);
// write js file, open external project and open it for edit
const jsFilePath = `${projectLocation}/javascript.js`;
host.writeFile(jsFilePath, "");
service.openExternalProjects([{
projectFileName,
rootFiles: [{ fileName: tsconfig.path }, { fileName: jsFilePath }],
options: { allowJs: false }
}]);
service.applyChangesInOpenFiles([
{ fileName: jsFilePath, scriptKind: ScriptKind.JS, content: "" }
], /*changedFiles*/ undefined, /*closedFiles*/ undefined);
checkNumberOfProjects(service, { configuredProjects: 1, inferredProjects: 1 });
checkProjectActualFiles(configProject, [tsconfig.path]);
const inferredProject = service.inferredProjects[0];
checkProjectActualFiles(inferredProject, [libFile.path, jsFilePath]);
// write jsconfig file
const jsConfig: File = {
path: `${projectLocation}/jsconfig.json`,
content: "{}"
};
// Dont invoke file creation watchers as the repro suggests
host.ensureFileOrFolder(jsConfig, /*ignoreWatchInvokedWithTriggerAsFileCreate*/ true);
// Open external project
service.openExternalProjects([{
projectFileName,
rootFiles: [{ fileName: jsConfig.path }, { fileName: tsconfig.path }, { fileName: jsFilePath }],
options: { allowJs: false }
}]);
checkNumberOfProjects(service, { configuredProjects: 2, inferredProjects: 1 });
checkProjectActualFiles(configProject, [tsconfig.path]);
assert.isTrue(inferredProject.isOrphan());
const jsConfigProject = service.configuredProjects.get(jsConfig.path.toLowerCase())!;
checkProjectActualFiles(jsConfigProject, [jsConfig.path, jsFilePath, libFile.path]);
});
});
}

View file

@ -57,8 +57,8 @@ namespace ts.projectSystem {
export const nullLogger: server.Logger = {
close: noop,
hasLevel: () => false,
loggingEnabled: () => false,
hasLevel: returnFalse,
loggingEnabled: returnFalse,
perftrc: noop,
info: noop,
msg: noop,
@ -80,6 +80,21 @@ namespace ts.projectSystem {
return { logger, hasErrorMsg: () => hasErrorMsg };
}
export function createLoggerWritingToConsole(): server.Logger {
const { close, startGroup, endGroup, getLogFileName } = nullLogger;
return {
close,
hasLevel: returnTrue,
loggingEnabled: returnTrue,
perftrc: s => console.log(s),
info: s => console.log(s),
msg: (s, type) => console.log(`${type}:: ${s}`),
startGroup,
endGroup,
getLogFileName
};
}
export class TestTypingsInstaller extends TI.TypingsInstaller implements server.ITypingsInstaller {
protected projectService!: server.ProjectService;
constructor(

View file

@ -103,6 +103,30 @@ namespace ts.projectSystem {
assert.isFalse(proj3.languageServiceEnabled);
});
it("should not crash when opening a file in a project with a disabled language service", () => {
const file1 = {
path: "/a/b/f1.js",
content: "let x =1;",
fileSize: 50 * 1024 * 1024
};
const file2 = {
path: "/a/b/f2.js",
content: "let x =1;",
fileSize: 100
};
const projName = "proj1";
const host = createServerHost([file1, file2]);
const projectService = createProjectService(host, { useSingleInferredProject: true }, { eventHandler: noop });
projectService.openExternalProject({ rootFiles: toExternalFiles([file1.path, file2.path]), options: {}, projectFileName: projName });
const proj1 = projectService.findProject(projName)!;
assert.isFalse(proj1.languageServiceEnabled);
assert.doesNotThrow(() => projectService.openClientFile(file2.path));
});
describe("ignoreConfigFiles", () => {
it("external project including config file", () => {
const file1 = {

View file

@ -116,5 +116,40 @@ namespace ts.projectSystem {
renameLocation: undefined,
});
});
it("handles canonicalization of tsconfig path", () => {
const aTs: File = { path: "/Foo/a.ts", content: "const x = 0;" };
const tsconfig: File = { path: "/Foo/tsconfig.json", content: '{ "files": ["./a.ts"] }' };
const session = createSession(createServerHost([aTs, tsconfig]));
openFilesForSession([aTs], session);
const result = executeSessionRequest<protocol.GetEditsForRefactorRequest, protocol.GetEditsForRefactorResponse>(session, protocol.CommandTypes.GetEditsForRefactor, {
file: aTs.path,
startLine: 1,
startOffset: 1,
endLine: 2,
endOffset: aTs.content.length,
refactor: "Move to a new file",
action: "Move to a new file",
});
assert.deepEqual<protocol.RefactorEditInfo | undefined>(result, {
edits: [
{
fileName: aTs.path,
textChanges: [{ start: { line: 1, offset: 1 }, end: { line: 1, offset: aTs.content.length + 1 }, newText: "" }],
},
{
fileName: tsconfig.path,
textChanges: [{ start: { line: 1, offset: 21 }, end: { line: 1, offset: 21 }, newText: ', "./x.ts"' }],
},
{
fileName: "/Foo/x.ts",
textChanges: [{ start: { line: 0, offset: 0 }, end: { line: 0, offset: 0 }, newText: "const x = 0;\n" }],
},
],
renameFilename: undefined,
renameLocation: undefined,
});
});
});
}

View file

@ -7,8 +7,18 @@ namespace ts.projectSystem {
const session = createSession(createServerHost([aTs, bTs]));
openFilesForSession([bTs], session);
const response = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, 'a";'));
assert.deepEqual<protocol.RenameResponseBody | undefined>(response, {
const response1 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, 'a";'));
assert.deepEqual<protocol.RenameResponseBody | undefined>(response1, {
info: {
canRename: false,
localizedErrorMessage: "You cannot rename this element."
},
locs: [{ file: bTs.path, locs: [protocolRenameSpanFromSubstring(bTs.content, "./a")] }],
});
session.getProjectService().setHostConfiguration({ preferences: { allowRenameOfImportPath: true } });
const response2 = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(bTs, 'a";'));
assert.deepEqual<protocol.RenameResponseBody | undefined>(response2, {
info: {
canRename: true,
fileToRename: aTs.path,

View file

@ -1,8 +1,8 @@
tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck14.ts(2,17): error TS2568: Type 'Set<number>' is not an array type. Use compiler option '--downlevelIteration' to allow iterating of iterators.
tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck14.ts(2,17): error TS2569: Type 'Set<number>' is not an array type or a string type. Use compiler option '--downlevelIteration' to allow iterating of iterators.
==== tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck14.ts (1 errors) ====
var union: string | Set<number>
for (const e of union) { }
~~~~~
!!! error TS2568: Type 'Set<number>' is not an array type. Use compiler option '--downlevelIteration' to allow iterating of iterators.
!!! error TS2569: Type 'Set<number>' is not an array type or a string type. Use compiler option '--downlevelIteration' to allow iterating of iterators.

View file

@ -4707,7 +4707,7 @@ declare namespace ts {
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TextSpan | undefined;
getBreakpointStatementAtPosition(fileName: string, position: number): TextSpan | undefined;
getSignatureHelpItems(fileName: string, position: number, options: SignatureHelpItemsOptions | undefined): SignatureHelpItems | undefined;
getRenameInfo(fileName: string, position: number): RenameInfo;
getRenameInfo(fileName: string, position: number, options?: RenameInfoOptions): RenameInfo;
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ReadonlyArray<RenameLocation> | undefined;
getDefinitionAtPosition(fileName: string, position: number): ReadonlyArray<DefinitionInfo> | undefined;
getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan | undefined;
@ -5151,6 +5151,9 @@ declare namespace ts {
canRename: false;
localizedErrorMessage: string;
}
interface RenameInfoOptions {
readonly allowRenameOfImportPath?: boolean;
}
interface SignatureHelpParameter {
name: string;
documentation: SymbolDisplayPart[];
@ -7924,6 +7927,7 @@ declare namespace ts.server.protocol {
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
readonly allowTextChangesInNewFiles?: boolean;
readonly lazyConfiguredProjectsFromExternalProject?: boolean;
readonly allowRenameOfImportPath?: boolean;
}
interface CompilerOptions {
allowJs?: boolean;

View file

@ -4707,7 +4707,7 @@ declare namespace ts {
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TextSpan | undefined;
getBreakpointStatementAtPosition(fileName: string, position: number): TextSpan | undefined;
getSignatureHelpItems(fileName: string, position: number, options: SignatureHelpItemsOptions | undefined): SignatureHelpItems | undefined;
getRenameInfo(fileName: string, position: number): RenameInfo;
getRenameInfo(fileName: string, position: number, options?: RenameInfoOptions): RenameInfo;
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): ReadonlyArray<RenameLocation> | undefined;
getDefinitionAtPosition(fileName: string, position: number): ReadonlyArray<DefinitionInfo> | undefined;
getDefinitionAndBoundSpan(fileName: string, position: number): DefinitionInfoAndBoundSpan | undefined;
@ -5151,6 +5151,9 @@ declare namespace ts {
canRename: false;
localizedErrorMessage: string;
}
interface RenameInfoOptions {
readonly allowRenameOfImportPath?: boolean;
}
interface SignatureHelpParameter {
name: string;
documentation: SymbolDisplayPart[];

View file

@ -1,6 +1,4 @@
tests/cases/conformance/jsx/file.tsx(42,11): error TS2322: Type '{ children: Element[]; a: number; b: string; }' is not assignable to type 'SingleChildProp'.
Types of property 'children' are incompatible.
Type 'Element[]' is missing the following properties from type 'Element': type, props
tests/cases/conformance/jsx/file.tsx(42,11): error TS2746: This JSX tag's 'children' prop expects a single child of type 'Element', but multiple children were provided.
==== tests/cases/conformance/jsx/file.tsx (1 errors) ====
@ -47,6 +45,4 @@ tests/cases/conformance/jsx/file.tsx(42,11): error TS2322: Type '{ children: Ele
// Error
let k5 = <SingleChildComp a={10} b="hi"><></><Button /><AnotherButton /></SingleChildComp>;
~~~~~~~~~~~~~~~
!!! error TS2322: Type '{ children: Element[]; a: number; b: string; }' is not assignable to type 'SingleChildProp'.
!!! error TS2322: Types of property 'children' are incompatible.
!!! error TS2322: Type 'Element[]' is missing the following properties from type 'Element': type, props
!!! error TS2746: This JSX tag's 'children' prop expects a single child of type 'Element', but multiple children were provided.

View file

@ -1,21 +1,9 @@
tests/cases/conformance/jsx/file.tsx(14,10): error TS2741: Property 'children' is missing in type '{ a: number; b: string; }' but required in type 'Prop'.
tests/cases/conformance/jsx/file.tsx(17,11): error TS2710: 'children' are specified twice. The attribute named 'children' will be overwritten.
tests/cases/conformance/jsx/file.tsx(31,6): error TS2322: Type '{ children: (Element | ((name: string) => Element))[]; a: number; b: string; }' is not assignable to type 'Prop'.
Types of property 'children' are incompatible.
Type '(Element | ((name: string) => Element))[]' is not assignable to type 'string | Element'.
Type '(Element | ((name: string) => Element))[]' is not assignable to type 'string'.
tests/cases/conformance/jsx/file.tsx(37,6): error TS2322: Type '{ children: (number | Element)[]; a: number; b: string; }' is not assignable to type 'Prop'.
Types of property 'children' are incompatible.
Type '(number | Element)[]' is not assignable to type 'string | Element'.
Type '(number | Element)[]' is not assignable to type 'string'.
tests/cases/conformance/jsx/file.tsx(43,6): error TS2322: Type '{ children: (string | Element)[]; a: number; b: string; }' is not assignable to type 'Prop'.
Types of property 'children' are incompatible.
Type '(string | Element)[]' is not assignable to type 'string | Element'.
Type '(string | Element)[]' is not assignable to type 'string'.
tests/cases/conformance/jsx/file.tsx(49,6): error TS2322: Type '{ children: Element[]; a: number; b: string; }' is not assignable to type 'Prop'.
Types of property 'children' are incompatible.
Type 'Element[]' is not assignable to type 'string | Element'.
Type 'Element[]' is not assignable to type 'string'.
tests/cases/conformance/jsx/file.tsx(31,6): error TS2746: This JSX tag's 'children' prop expects a single child of type 'string | Element', but multiple children were provided.
tests/cases/conformance/jsx/file.tsx(37,6): error TS2746: This JSX tag's 'children' prop expects a single child of type 'string | Element', but multiple children were provided.
tests/cases/conformance/jsx/file.tsx(43,6): error TS2746: This JSX tag's 'children' prop expects a single child of type 'string | Element', but multiple children were provided.
tests/cases/conformance/jsx/file.tsx(49,6): error TS2746: This JSX tag's 'children' prop expects a single child of type 'string | Element', but multiple children were provided.
==== tests/cases/conformance/jsx/file.tsx (6 errors) ====
@ -56,10 +44,7 @@ tests/cases/conformance/jsx/file.tsx(49,6): error TS2322: Type '{ children: Elem
let k2 =
<Comp a={10} b="hi">
~~~~
!!! error TS2322: Type '{ children: (Element | ((name: string) => Element))[]; a: number; b: string; }' is not assignable to type 'Prop'.
!!! error TS2322: Types of property 'children' are incompatible.
!!! error TS2322: Type '(Element | ((name: string) => Element))[]' is not assignable to type 'string | Element'.
!!! error TS2322: Type '(Element | ((name: string) => Element))[]' is not assignable to type 'string'.
!!! error TS2746: This JSX tag's 'children' prop expects a single child of type 'string | Element', but multiple children were provided.
<div> My Div </div>
{(name: string) => <div> My name {name} </div>}
</Comp>;
@ -67,10 +52,7 @@ tests/cases/conformance/jsx/file.tsx(49,6): error TS2322: Type '{ children: Elem
let k3 =
<Comp a={10} b="hi">
~~~~
!!! error TS2322: Type '{ children: (number | Element)[]; a: number; b: string; }' is not assignable to type 'Prop'.
!!! error TS2322: Types of property 'children' are incompatible.
!!! error TS2322: Type '(number | Element)[]' is not assignable to type 'string | Element'.
!!! error TS2322: Type '(number | Element)[]' is not assignable to type 'string'.
!!! error TS2746: This JSX tag's 'children' prop expects a single child of type 'string | Element', but multiple children were provided.
<div> My Div </div>
{1000000}
</Comp>;
@ -78,10 +60,7 @@ tests/cases/conformance/jsx/file.tsx(49,6): error TS2322: Type '{ children: Elem
let k4 =
<Comp a={10} b="hi" >
~~~~
!!! error TS2322: Type '{ children: (string | Element)[]; a: number; b: string; }' is not assignable to type 'Prop'.
!!! error TS2322: Types of property 'children' are incompatible.
!!! error TS2322: Type '(string | Element)[]' is not assignable to type 'string | Element'.
!!! error TS2322: Type '(string | Element)[]' is not assignable to type 'string'.
!!! error TS2746: This JSX tag's 'children' prop expects a single child of type 'string | Element', but multiple children were provided.
<div> My Div </div>
hi hi hi!
</Comp>;
@ -89,10 +68,7 @@ tests/cases/conformance/jsx/file.tsx(49,6): error TS2322: Type '{ children: Elem
let k5 =
<Comp a={10} b="hi" >
~~~~
!!! error TS2322: Type '{ children: Element[]; a: number; b: string; }' is not assignable to type 'Prop'.
!!! error TS2322: Types of property 'children' are incompatible.
!!! error TS2322: Type 'Element[]' is not assignable to type 'string | Element'.
!!! error TS2322: Type 'Element[]' is not assignable to type 'string'.
!!! error TS2746: This JSX tag's 'children' prop expects a single child of type 'string | Element', but multiple children were provided.
<div> My Div </div>
<div> My Div </div>
</Comp>;

View file

@ -1,11 +1,11 @@
tests/cases/conformance/jsx/file.tsx(24,28): error TS2551: Property 'NAme' does not exist on type 'IUser'. Did you mean 'Name'?
tests/cases/conformance/jsx/file.tsx(32,10): error TS2322: Type '{ children: (((user: IUser) => Element) | ((user: IUser) => Element))[]; }' is not assignable to type 'IFetchUserProps'.
Types of property 'children' are incompatible.
Type '(((user: IUser) => Element) | ((user: IUser) => Element))[]' is not assignable to type '(user: IUser) => Element'.
Type '(((user: IUser) => Element) | ((user: IUser) => Element))[]' provides no match for the signature '(user: IUser): Element'.
tests/cases/conformance/jsx/file.tsx(36,15): error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | any[] | ReactElement<any>'.
Type '(user: IUser) => Element' is missing the following properties from type 'ReactElement<any>': type, props
tests/cases/conformance/jsx/file.tsx(39,15): error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | any[] | ReactElement<any>'.
Type '(user: IUser) => Element' is missing the following properties from type 'ReactElement<any>': type, props
==== tests/cases/conformance/jsx/file.tsx (2 errors) ====
==== tests/cases/conformance/jsx/file.tsx (3 errors) ====
import React = require('react');
interface IUser {
@ -41,20 +41,27 @@ tests/cases/conformance/jsx/file.tsx(32,10): error TS2322: Type '{ children: (((
function UserName1() {
return (
<FetchUser>
~~~~~~~~~
!!! error TS2322: Type '{ children: (((user: IUser) => Element) | ((user: IUser) => Element))[]; }' is not assignable to type 'IFetchUserProps'.
!!! error TS2322: Types of property 'children' are incompatible.
!!! error TS2322: Type '(((user: IUser) => Element) | ((user: IUser) => Element))[]' is not assignable to type '(user: IUser) => Element'.
!!! error TS2322: Type '(((user: IUser) => Element) | ((user: IUser) => Element))[]' provides no match for the signature '(user: IUser): Element'.
{ user => (
~~~~~~~~~
<h1>{ user.Name }</h1>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
) }
~~~~~~~~~~~~~
!!! error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | any[] | ReactElement<any>'.
!!! error TS2322: Type '(user: IUser) => Element' is missing the following properties from type 'ReactElement<any>': type, props
!!! related TS6212 tests/cases/conformance/jsx/file.tsx:36:15: Did you mean to call this expression?
{ user => (
~~~~~~~~~
<h1>{ user.Name }</h1>
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
) }
~~~~~~~~~~~~~
!!! error TS2322: Type '(user: IUser) => Element' is not assignable to type 'string | number | boolean | any[] | ReactElement<any>'.
!!! error TS2322: Type '(user: IUser) => Element' is missing the following properties from type 'ReactElement<any>': type, props
!!! related TS6212 tests/cases/conformance/jsx/file.tsx:39:15: Did you mean to call this expression?
</FetchUser>
);
}

View file

@ -1,10 +1,6 @@
tests/cases/conformance/jsx/file.tsx(20,10): error TS2741: Property 'children' is missing in type '{ a: number; b: string; }' but required in type 'Prop'.
tests/cases/conformance/jsx/file.tsx(24,6): error TS2322: Type '{ children: Element; a: number; b: string; }' is not assignable to type 'Prop'.
Types of property 'children' are incompatible.
Type 'Element' is missing the following properties from type 'Button': render, setState, forceUpdate, state, and 2 more.
tests/cases/conformance/jsx/file.tsx(28,6): error TS2322: Type '{ children: typeof Button; a: number; b: string; }' is not assignable to type 'Prop'.
Types of property 'children' are incompatible.
Type 'typeof Button' is missing the following properties from type 'Button': render, setState, forceUpdate, props, and 3 more.
tests/cases/conformance/jsx/file.tsx(25,9): error TS2740: Type 'Element' is missing the following properties from type 'Button': render, setState, forceUpdate, state, and 2 more.
tests/cases/conformance/jsx/file.tsx(29,10): error TS2740: Type 'typeof Button' is missing the following properties from type 'Button': render, setState, forceUpdate, props, and 3 more.
==== tests/cases/conformance/jsx/file.tsx (3 errors) ====
@ -35,17 +31,15 @@ tests/cases/conformance/jsx/file.tsx(28,6): error TS2322: Type '{ children: type
// Error: JSX.element is not the same as JSX.ElementClass
let k1 =
<Comp a={10} b="hi">
~~~~
!!! error TS2322: Type '{ children: Element; a: number; b: string; }' is not assignable to type 'Prop'.
!!! error TS2322: Types of property 'children' are incompatible.
!!! error TS2322: Type 'Element' is missing the following properties from type 'Button': render, setState, forceUpdate, state, and 2 more.
<Button />
~~~~~~~~~~
!!! error TS2740: Type 'Element' is missing the following properties from type 'Button': render, setState, forceUpdate, state, and 2 more.
!!! related TS6500 tests/cases/conformance/jsx/file.tsx:6:5: The expected type comes from property 'children' which is declared here on type 'IntrinsicAttributes & Prop'
</Comp>;
let k2 =
<Comp a={10} b="hi">
~~~~
!!! error TS2322: Type '{ children: typeof Button; a: number; b: string; }' is not assignable to type 'Prop'.
!!! error TS2322: Types of property 'children' are incompatible.
!!! error TS2322: Type 'typeof Button' is missing the following properties from type 'Button': render, setState, forceUpdate, props, and 3 more.
{Button}
~~~~~~
!!! error TS2740: Type 'typeof Button' is missing the following properties from type 'Button': render, setState, forceUpdate, props, and 3 more.
!!! related TS6213 tests/cases/conformance/jsx/file.tsx:29:10: Did you mean to use 'new' with this expression?
</Comp>;

View file

@ -1,17 +1,6 @@
tests/cases/conformance/jsx/file.tsx(24,11): error TS2322: Type '{ children: (string | Element)[]; a: number; b: string; }' is not assignable to type 'Prop'.
Types of property 'children' are incompatible.
Type '(string | Element)[]' is not assignable to type 'Element | Element[]'.
Type '(string | Element)[]' is not assignable to type 'Element[]'.
Type 'string | Element' is not assignable to type 'Element'.
Type 'string' is not assignable to type 'Element'.
tests/cases/conformance/jsx/file.tsx(25,11): error TS2322: Type '{ children: (string | Element)[]; a: number; b: string; }' is not assignable to type 'Prop'.
Types of property 'children' are incompatible.
Type '(string | Element)[]' is not assignable to type 'Element | Element[]'.
Type '(string | Element)[]' is not assignable to type 'Element[]'.
tests/cases/conformance/jsx/file.tsx(27,11): error TS2322: Type '{ children: (string | Element)[]; a: number; b: string; }' is not assignable to type 'Prop'.
Types of property 'children' are incompatible.
Type '(string | Element)[]' is not assignable to type 'Element | Element[]'.
Type '(string | Element)[]' is not assignable to type 'Element[]'.
tests/cases/conformance/jsx/file.tsx(24,40): error TS2747: 'Comp' components don't accept text as child elements. Text in JSX has the type 'string', but the expected type of 'children' is 'Element | Element[]'.
tests/cases/conformance/jsx/file.tsx(26,22): error TS2747: 'Comp' components don't accept text as child elements. Text in JSX has the type 'string', but the expected type of 'children' is 'Element | Element[]'.
tests/cases/conformance/jsx/file.tsx(27,30): error TS2747: 'Comp' components don't accept text as child elements. Text in JSX has the type 'string', but the expected type of 'children' is 'Element | Element[]'.
==== tests/cases/conformance/jsx/file.tsx (3 errors) ====
@ -39,24 +28,13 @@ tests/cases/conformance/jsx/file.tsx(27,11): error TS2322: Type '{ children: (st
// Error: whitespaces matters
let k1 = <Comp a={10} b="hi"><Button /> <AnotherButton /></Comp>;
~~~~
!!! error TS2322: Type '{ children: (string | Element)[]; a: number; b: string; }' is not assignable to type 'Prop'.
!!! error TS2322: Types of property 'children' are incompatible.
!!! error TS2322: Type '(string | Element)[]' is not assignable to type 'Element | Element[]'.
!!! error TS2322: Type '(string | Element)[]' is not assignable to type 'Element[]'.
!!! error TS2322: Type 'string | Element' is not assignable to type 'Element'.
!!! error TS2322: Type 'string' is not assignable to type 'Element'.
~~
!!! error TS2747: 'Comp' components don't accept text as child elements. Text in JSX has the type 'string', but the expected type of 'children' is 'Element | Element[]'.
let k2 = <Comp a={10} b="hi"><Button />
~~~~
!!! error TS2322: Type '{ children: (string | Element)[]; a: number; b: string; }' is not assignable to type 'Prop'.
!!! error TS2322: Types of property 'children' are incompatible.
!!! error TS2322: Type '(string | Element)[]' is not assignable to type 'Element | Element[]'.
!!! error TS2322: Type '(string | Element)[]' is not assignable to type 'Element[]'.
<AnotherButton /> </Comp>;
~~
!!! error TS2747: 'Comp' components don't accept text as child elements. Text in JSX has the type 'string', but the expected type of 'children' is 'Element | Element[]'.
let k3 = <Comp a={10} b="hi"> <Button />
~~~~
!!! error TS2322: Type '{ children: (string | Element)[]; a: number; b: string; }' is not assignable to type 'Prop'.
!!! error TS2322: Types of property 'children' are incompatible.
!!! error TS2322: Type '(string | Element)[]' is not assignable to type 'Element | Element[]'.
!!! error TS2322: Type '(string | Element)[]' is not assignable to type 'Element[]'.
~~~~
!!! error TS2747: 'Comp' components don't accept text as child elements. Text in JSX has the type 'string', but the expected type of 'children' is 'Element | Element[]'.
<AnotherButton /></Comp>;

View file

@ -0,0 +1,22 @@
tests/cases/compiler/noSuperInJSDocExtends.js(14,9): error TS2335: 'super' can only be referenced in a derived class.
==== tests/cases/compiler/noSuperInJSDocExtends.js (1 errors) ====
class Based { }
/** @extends {Based} */
class Derived {
constructor() {
this;
this.x = 10;
var that = this;
}
}
/** @extends {Based} */
class Derived2 {
constructor() {
super();
~~~~~
!!! error TS2335: 'super' can only be referenced in a derived class.
}
}

View file

@ -0,0 +1,31 @@
=== tests/cases/compiler/noSuperInJSDocExtends.js ===
class Based { }
>Based : Symbol(Based, Decl(noSuperInJSDocExtends.js, 0, 0))
/** @extends {Based} */
class Derived {
>Derived : Symbol(Derived, Decl(noSuperInJSDocExtends.js, 0, 15))
constructor() {
this;
>this : Symbol(Derived, Decl(noSuperInJSDocExtends.js, 0, 15))
this.x = 10;
>this.x : Symbol(Derived.x, Decl(noSuperInJSDocExtends.js, 4, 13))
>this : Symbol(Derived, Decl(noSuperInJSDocExtends.js, 0, 15))
>x : Symbol(Derived.x, Decl(noSuperInJSDocExtends.js, 4, 13))
var that = this;
>that : Symbol(that, Decl(noSuperInJSDocExtends.js, 6, 11))
>this : Symbol(Derived, Decl(noSuperInJSDocExtends.js, 0, 15))
}
}
/** @extends {Based} */
class Derived2 {
>Derived2 : Symbol(Derived2, Decl(noSuperInJSDocExtends.js, 8, 1))
constructor() {
super();
}
}

View file

@ -0,0 +1,35 @@
=== tests/cases/compiler/noSuperInJSDocExtends.js ===
class Based { }
>Based : Based
/** @extends {Based} */
class Derived {
>Derived : Derived
constructor() {
this;
>this : this
this.x = 10;
>this.x = 10 : 10
>this.x : number
>this : this
>x : number
>10 : 10
var that = this;
>that : this
>this : this
}
}
/** @extends {Based} */
class Derived2 {
>Derived2 : Derived2
constructor() {
super();
>super() : void
>super : any
}
}

View file

@ -471,4 +471,12 @@ tests/cases/conformance/types/conditional/conditionalTypes1.ts(288,43): error TS
var a = {o: 1, b: 2, c: [{a: 1, c: '213'}]}
assign(a, {o: 2, c: {0: {a: 2, c: '213123'}}})
// Repros from #23843
type Weird1 = (<U extends boolean>(a: U) => never) extends
(<U extends true>(a: U) => never) ? never : never;
type Weird2 = (<U extends boolean>(a: U) => U) extends
(<U extends true>(a: U) => infer T) ? T : never;

View file

@ -351,6 +351,14 @@ declare function assign<T>(o: T, a: RecursivePartial<T>): void;
var a = {o: 1, b: 2, c: [{a: 1, c: '213'}]}
assign(a, {o: 2, c: {0: {a: 2, c: '213123'}}})
// Repros from #23843
type Weird1 = (<U extends boolean>(a: U) => never) extends
(<U extends true>(a: U) => never) ? never : never;
type Weird2 = (<U extends boolean>(a: U) => U) extends
(<U extends true>(a: U) => infer T) ? T : never;
//// [conditionalTypes1.js]
@ -715,3 +723,5 @@ declare var a: {
c: string;
}[];
};
declare type Weird1 = (<U extends boolean>(a: U) => never) extends (<U extends true>(a: U) => never) ? never : never;
declare type Weird2 = (<U extends boolean>(a: U) => U) extends (<U extends true>(a: U) => infer T) ? T : never;

View file

@ -1371,3 +1371,30 @@ assign(a, {o: 2, c: {0: {a: 2, c: '213123'}}})
>a : Symbol(a, Decl(conditionalTypes1.ts, 351, 25))
>c : Symbol(c, Decl(conditionalTypes1.ts, 351, 30))
// Repros from #23843
type Weird1 = (<U extends boolean>(a: U) => never) extends
>Weird1 : Symbol(Weird1, Decl(conditionalTypes1.ts, 351, 46))
>U : Symbol(U, Decl(conditionalTypes1.ts, 355, 16))
>a : Symbol(a, Decl(conditionalTypes1.ts, 355, 35))
>U : Symbol(U, Decl(conditionalTypes1.ts, 355, 16))
(<U extends true>(a: U) => never) ? never : never;
>U : Symbol(U, Decl(conditionalTypes1.ts, 356, 6))
>a : Symbol(a, Decl(conditionalTypes1.ts, 356, 22))
>U : Symbol(U, Decl(conditionalTypes1.ts, 356, 6))
type Weird2 = (<U extends boolean>(a: U) => U) extends
>Weird2 : Symbol(Weird2, Decl(conditionalTypes1.ts, 356, 54))
>U : Symbol(U, Decl(conditionalTypes1.ts, 358, 16))
>a : Symbol(a, Decl(conditionalTypes1.ts, 358, 35))
>U : Symbol(U, Decl(conditionalTypes1.ts, 358, 16))
>U : Symbol(U, Decl(conditionalTypes1.ts, 358, 16))
(<U extends true>(a: U) => infer T) ? T : never;
>U : Symbol(U, Decl(conditionalTypes1.ts, 359, 6))
>a : Symbol(a, Decl(conditionalTypes1.ts, 359, 22))
>U : Symbol(U, Decl(conditionalTypes1.ts, 359, 6))
>T : Symbol(T, Decl(conditionalTypes1.ts, 359, 36))
>T : Symbol(T, Decl(conditionalTypes1.ts, 359, 36))

View file

@ -1054,3 +1054,21 @@ assign(a, {o: 2, c: {0: {a: 2, c: '213123'}}})
>c : string
>'213123' : "213123"
// Repros from #23843
type Weird1 = (<U extends boolean>(a: U) => never) extends
>Weird1 : never
>a : U
(<U extends true>(a: U) => never) ? never : never;
>true : true
>a : U
type Weird2 = (<U extends boolean>(a: U) => U) extends
>Weird2 : boolean
>a : U
(<U extends true>(a: U) => infer T) ? T : never;
>true : true
>a : U

View file

@ -0,0 +1,16 @@
// ==ORIGINAL==
function foo() {
return fetch('a').then(/*[#|*/() => {/*|]*/
return fetch('b').then(() => 'c');
})
}
// ==ASYNC FUNCTION::Convert to async function==
function foo() {
return fetch('a').then(async () => {
await fetch('b');
return 'c';
})
}

View file

@ -0,0 +1,15 @@
// ==ORIGINAL==
function /*[#|*/foo/*|]*/() {
return fetch('a').then(() => {
return fetch('b').then(() => 'c');
})
}
// ==ASYNC FUNCTION::Convert to async function==
async function foo() {
await fetch('a');
await fetch('b');
return 'c';
}

View file

@ -0,0 +1,15 @@
// ==ORIGINAL==
function /*[#|*/foo/*|]*/() {
return fetch('a').then(() => {
return fetch('b').then(() => 'c');
})
}
// ==ASYNC FUNCTION::Convert to async function==
async function foo() {
await fetch('a');
await fetch('b');
return 'c';
}

View file

@ -5,7 +5,7 @@ function /*[#|*/f/*|]*/() {
}
function res({ status, trailer }){
console.log(status);
}
}
// ==ASYNC FUNCTION::Convert to async function==
@ -15,4 +15,4 @@ async function f() {
}
function res({ status, trailer }){
console.log(status);
}
}

View file

@ -5,7 +5,7 @@ function /*[#|*/f/*|]*/() {
}
function res({ status, trailer }){
console.log(status);
}
}
// ==ASYNC FUNCTION::Convert to async function==
@ -15,4 +15,4 @@ async function f() {
}
function res({ status, trailer }){
console.log(status);
}
}

View file

@ -6,7 +6,7 @@ function /*[#|*/f/*|]*/() {
}
function res({ status, trailer }){
console.log(status);
}
}
// ==ASYNC FUNCTION::Convert to async function==
@ -17,4 +17,4 @@ async function f() {
}
function res({ status, trailer }){
console.log(status);
}
}

View file

@ -6,7 +6,7 @@ function /*[#|*/f/*|]*/() {
}
function res({ status, trailer }){
console.log(status);
}
}
// ==ASYNC FUNCTION::Convert to async function==
@ -17,4 +17,4 @@ async function f() {
}
function res({ status, trailer }){
console.log(status);
}
}

View file

@ -4,7 +4,7 @@ function /*[#|*/f/*|]*/() {
return Promise.resolve(1)
.then(x => Promise.reject(x))
.catch(err => console.log(err));
}
}
// ==ASYNC FUNCTION::Convert to async function==
@ -16,4 +16,4 @@ async function f() {
catch (err) {
return console.log(err);
}
}
}

View file

@ -4,7 +4,7 @@ function /*[#|*/f/*|]*/() {
return Promise.resolve(1)
.then(x => Promise.reject(x))
.catch(err => console.log(err));
}
}
// ==ASYNC FUNCTION::Convert to async function==
@ -16,4 +16,4 @@ async function f() {
catch (err) {
return console.log(err);
}
}
}

View file

@ -1,8 +1,8 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/() {
return Promise.resolve().then(x => 1).catch(x => "a").then(x => !!x);
}
return Promise.resolve().then(x => 1).catch(x => "a").then(x => !!x);
}
// ==ASYNC FUNCTION::Convert to async function==
@ -15,5 +15,5 @@ async function f() {
catch (x_1) {
x_2 = "a";
}
return !!x_2;
}
return !!x_2;
}

View file

@ -1,8 +1,8 @@
// ==ORIGINAL==
function /*[#|*/f/*|]*/() {
return Promise.resolve().then(x => 1).catch(x => "a").then(x => !!x);
}
return Promise.resolve().then(x => 1).catch(x => "a").then(x => !!x);
}
// ==ASYNC FUNCTION::Convert to async function==
@ -15,5 +15,5 @@ async function f() {
catch (x_1) {
x_2 = "a";
}
return !!x_2;
}
return !!x_2;
}

View file

@ -5,7 +5,7 @@ function /*[#|*/f/*|]*/() {
}
function res(result) {
return Promise.resolve().then(x => console.log(result));
}
}
// ==ASYNC FUNCTION::Convert to async function==
@ -16,4 +16,4 @@ async function f() {
}
function res(result) {
return Promise.resolve().then(x => console.log(result));
}
}

View file

@ -5,7 +5,7 @@ function /*[#|*/f/*|]*/() {
}
function res(result) {
return Promise.resolve().then(x => console.log(result));
}
}
// ==ASYNC FUNCTION::Convert to async function==
@ -16,4 +16,4 @@ async function f() {
}
function res(result) {
return Promise.resolve().then(x => console.log(result));
}
}

View file

@ -2,11 +2,11 @@
const /*[#|*/foo/*|]*/ = function () {
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
}
}
// ==ASYNC FUNCTION::Convert to async function==
const foo = async function () {
const result = await fetch('https://typescriptlang.org');
console.log(result);
}
}

View file

@ -2,11 +2,11 @@
const /*[#|*/foo/*|]*/ = function () {
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
}
}
// ==ASYNC FUNCTION::Convert to async function==
const foo = async function () {
const result = await fetch('https://typescriptlang.org');
console.log(result);
}
}

View file

@ -2,11 +2,11 @@
const { length } = /*[#|*/function/*|]*/ () {
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
}
}
// ==ASYNC FUNCTION::Convert to async function==
const { length } = async function () {
const result = await fetch('https://typescriptlang.org');
console.log(result);
}
}

View file

@ -2,11 +2,11 @@
const { length } = /*[#|*/function/*|]*/ () {
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
}
}
// ==ASYNC FUNCTION::Convert to async function==
const { length } = async function () {
const result = await fetch('https://typescriptlang.org');
console.log(result);
}
}

View file

@ -2,11 +2,11 @@
const foo = function /*[#|*/f/*|]*/() {
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
}
}
// ==ASYNC FUNCTION::Convert to async function==
const foo = async function f() {
const result = await fetch('https://typescriptlang.org');
console.log(result);
}
}

View file

@ -2,11 +2,11 @@
const foo = function /*[#|*/f/*|]*/() {
return fetch('https://typescriptlang.org').then(result => { console.log(result) });
}
}
// ==ASYNC FUNCTION::Convert to async function==
const foo = async function f() {
const result = await fetch('https://typescriptlang.org');
console.log(result);
}
}

View file

@ -0,0 +1,7 @@
// [source.js.map]
{"version":3,"file":"source.js","sourceRoot":"","sources":["source.ts","another.html"],"names":[],"mappings":"AAAA,iCACyB,CAAA;ACDzB,QAAS,CDED"}
// [source.js]
"multi\n line";
'change';
//# sourceMappingURL=source.js.map

View file

@ -0,0 +1,54 @@
//// [declarationEmitLocalClassHasRequiredDeclare.ts]
export declare namespace A {
namespace X { }
}
class X { }
export class A {
static X = X;
}
export declare namespace Y {
}
export class Y { }
//// [declarationEmitLocalClassHasRequiredDeclare.js]
"use strict";
exports.__esModule = true;
var X = /** @class */ (function () {
function X() {
}
return X;
}());
var A = /** @class */ (function () {
function A() {
}
A.X = X;
return A;
}());
exports.A = A;
var Y = /** @class */ (function () {
function Y() {
}
return Y;
}());
exports.Y = Y;
//// [declarationEmitLocalClassHasRequiredDeclare.d.ts]
export declare namespace A {
namespace X { }
}
declare class X {
}
export declare class A {
static X: typeof X;
}
export declare namespace Y {
}
export declare class Y {
}
export {};

View file

@ -0,0 +1,27 @@
=== tests/cases/compiler/declarationEmitLocalClassHasRequiredDeclare.ts ===
export declare namespace A {
>A : Symbol(A, Decl(declarationEmitLocalClassHasRequiredDeclare.ts, 0, 0), Decl(declarationEmitLocalClassHasRequiredDeclare.ts, 4, 11))
namespace X { }
>X : Symbol(X, Decl(declarationEmitLocalClassHasRequiredDeclare.ts, 0, 28), Decl(declarationEmitLocalClassHasRequiredDeclare.ts, 6, 16))
}
class X { }
>X : Symbol(X, Decl(declarationEmitLocalClassHasRequiredDeclare.ts, 2, 1))
export class A {
>A : Symbol(A, Decl(declarationEmitLocalClassHasRequiredDeclare.ts, 0, 0), Decl(declarationEmitLocalClassHasRequiredDeclare.ts, 4, 11))
static X = X;
>X : Symbol(A.X, Decl(declarationEmitLocalClassHasRequiredDeclare.ts, 0, 28), Decl(declarationEmitLocalClassHasRequiredDeclare.ts, 6, 16))
>X : Symbol(X, Decl(declarationEmitLocalClassHasRequiredDeclare.ts, 2, 1))
}
export declare namespace Y {
>Y : Symbol(Y, Decl(declarationEmitLocalClassHasRequiredDeclare.ts, 8, 1), Decl(declarationEmitLocalClassHasRequiredDeclare.ts, 12, 1))
}
export class Y { }
>Y : Symbol(Y, Decl(declarationEmitLocalClassHasRequiredDeclare.ts, 8, 1), Decl(declarationEmitLocalClassHasRequiredDeclare.ts, 12, 1))

View file

@ -0,0 +1,23 @@
=== tests/cases/compiler/declarationEmitLocalClassHasRequiredDeclare.ts ===
export declare namespace A {
namespace X { }
}
class X { }
>X : X
export class A {
>A : A
static X = X;
>X : typeof X
>X : typeof X
}
export declare namespace Y {
}
export class Y { }
>Y : Y

View file

@ -0,0 +1,28 @@
//// [decoratorWithNegativeLiteralTypeNoCrash.ts]
class A {
@decorator
public field1: -1 = -1;
}
function decorator(target: any, field: any) {}
//// [decoratorWithNegativeLiteralTypeNoCrash.js]
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var A = /** @class */ (function () {
function A() {
this.field1 = -1;
}
__decorate([
decorator,
__metadata("design:type", Number)
], A.prototype, "field1", void 0);
return A;
}());
function decorator(target, field) { }

View file

@ -0,0 +1,15 @@
=== tests/cases/compiler/decoratorWithNegativeLiteralTypeNoCrash.ts ===
class A {
>A : Symbol(A, Decl(decoratorWithNegativeLiteralTypeNoCrash.ts, 0, 0))
@decorator
>decorator : Symbol(decorator, Decl(decoratorWithNegativeLiteralTypeNoCrash.ts, 3, 1))
public field1: -1 = -1;
>field1 : Symbol(A.field1, Decl(decoratorWithNegativeLiteralTypeNoCrash.ts, 0, 9))
}
function decorator(target: any, field: any) {}
>decorator : Symbol(decorator, Decl(decoratorWithNegativeLiteralTypeNoCrash.ts, 3, 1))
>target : Symbol(target, Decl(decoratorWithNegativeLiteralTypeNoCrash.ts, 4, 19))
>field : Symbol(field, Decl(decoratorWithNegativeLiteralTypeNoCrash.ts, 4, 31))

View file

@ -0,0 +1,19 @@
=== tests/cases/compiler/decoratorWithNegativeLiteralTypeNoCrash.ts ===
class A {
>A : A
@decorator
>decorator : (target: any, field: any) => void
public field1: -1 = -1;
>field1 : -1
>-1 : -1
>1 : 1
>-1 : -1
>1 : 1
}
function decorator(target: any, field: any) {}
>decorator : (target: any, field: any) => void
>target : any
>field : any

View file

@ -45,8 +45,8 @@ const [f, g = f, h = i, i = f] = [1]; // error for h = i
>c : number
>d : number
>c : number
>e : number
>e : number
>e : any
>e : any
})([1]);
>[1] : number[]

View file

@ -17,9 +17,16 @@ const Child: SFC<Props> = ({
children,
name = "Artemis",
...props
}) => `name: ${name} props: ${JSON.stringify(props)}`;
}) => `name: ${name} props: ${JSON.stringify(props)}`;
// Repro from #29189
declare function f(g: (as: string[]) => void): void
f(([_1, _2 = undefined]) => undefined)
//// [destructuringInitializerContextualTypeFromContext.js]
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
@ -48,3 +55,7 @@ var Child = function (_a) {
var children = _a.children, _b = _a.name, name = _b === void 0 ? "Artemis" : _b, props = __rest(_a, ["children", "name"]);
return "name: " + name + " props: " + JSON.stringify(props);
};
f(function (_a) {
var _1 = _a[0], _b = _a[1], _2 = _b === void 0 ? undefined : _b;
return undefined;
});

View file

@ -56,3 +56,17 @@ const Child: SFC<Props> = ({
>stringify : Symbol(JSON.stringify, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>props : Symbol(props, Decl(destructuringInitializerContextualTypeFromContext.ts, 16, 21))
// Repro from #29189
declare function f(g: (as: string[]) => void): void
>f : Symbol(f, Decl(destructuringInitializerContextualTypeFromContext.ts, 18, 54))
>g : Symbol(g, Decl(destructuringInitializerContextualTypeFromContext.ts, 22, 19))
>as : Symbol(as, Decl(destructuringInitializerContextualTypeFromContext.ts, 22, 23))
f(([_1, _2 = undefined]) => undefined)
>f : Symbol(f, Decl(destructuringInitializerContextualTypeFromContext.ts, 18, 54))
>_1 : Symbol(_1, Decl(destructuringInitializerContextualTypeFromContext.ts, 23, 4))
>_2 : Symbol(_2, Decl(destructuringInitializerContextualTypeFromContext.ts, 23, 7))
>undefined : Symbol(undefined)
>undefined : Symbol(undefined)

View file

@ -50,8 +50,24 @@ const Child: SFC<Props> = ({
>`name: ${name} props: ${JSON.stringify(props)}` : string
>name : "Apollo" | "Artemis" | "Dionysus" | "Persephone"
>JSON.stringify(props) : string
>JSON.stringify : { (value: any, replacer?: (key: string, value: any) => any, space?: string | number): string; (value: any, replacer?: (string | number)[], space?: string | number): string; }
>JSON.stringify : { (value: any, replacer?: ((key: string, value: any) => any) | undefined, space?: string | number | undefined): string; (value: any, replacer?: (string | number)[] | null | undefined, space?: string | number | undefined): string; }
>JSON : JSON
>stringify : { (value: any, replacer?: (key: string, value: any) => any, space?: string | number): string; (value: any, replacer?: (string | number)[], space?: string | number): string; }
>stringify : { (value: any, replacer?: ((key: string, value: any) => any) | undefined, space?: string | number | undefined): string; (value: any, replacer?: (string | number)[] | null | undefined, space?: string | number | undefined): string; }
>props : {}
// Repro from #29189
declare function f(g: (as: string[]) => void): void
>f : (g: (as: string[]) => void) => void
>g : (as: string[]) => void
>as : string[]
f(([_1, _2 = undefined]) => undefined)
>f(([_1, _2 = undefined]) => undefined) : void
>f : (g: (as: string[]) => void) => void
>([_1, _2 = undefined]) => undefined : ([_1, _2]: string[]) => undefined
>_1 : string
>_2 : string | undefined
>undefined : undefined
>undefined : undefined

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