Merge branch 'master' into es2019
This commit is contained in:
commit
d8ac9ba414
5
completionAtDottedNamespace.ts
Normal file
5
completionAtDottedNamespace.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
////namespace wwer./**/w
|
||||
|
||||
verify.completions({ marker: "", exact: [], isNewIdentifierLocation: true });
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
"module": "commonjs",
|
||||
"outDir": "../../built/local/tslint",
|
||||
"baseUrl": "../..",
|
||||
"types": ["node"],
|
||||
"paths": {
|
||||
"typescript": ["lib/typescript.d.ts"]
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1898,6 +1898,7 @@ namespace ts {
|
|||
case SyntaxKind.StringLiteral:
|
||||
return createIdentifier("String");
|
||||
|
||||
case SyntaxKind.PrefixUnaryExpression:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
return createIdentifier("Number");
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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" />
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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 } });
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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) };
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 };
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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))!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
24
src/services/codefixes/fixEnableExperimentalDecorators.ts
Normal file
24
src/services/codefixes/fixEnableExperimentalDecorators.ts
Normal 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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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[] = [];
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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()}`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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[];
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 }
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
|
|
307
src/testRunner/unittests/tscWatch/emitAndErrorUpdates.ts
Normal file
307
src/testRunner/unittests/tscWatch/emitAndErrorUpdates.ts
Normal 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
|
@ -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;
|
||||
|
|
|
@ -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[];
|
||||
|
|
|
@ -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.
|
|
@ -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>;
|
|
@ -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>
|
||||
);
|
||||
}
|
|
@ -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>;
|
|
@ -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>;
|
|
@ -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.
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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';
|
||||
})
|
||||
}
|
|
@ -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';
|
||||
}
|
|
@ -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';
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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 {};
|
|
@ -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))
|
||||
|
|
@ -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
|
||||
|
|
@ -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) { }
|
|
@ -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))
|
||||
|
|
@ -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
|
||||
|
|
@ -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[]
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue