diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 782363dd6df..86c9c97bdd5 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -2071,7 +2071,7 @@ namespace ts { seenThisKeyword = true; return; case SyntaxKind.TypePredicate: - return checkTypePredicate(node as TypePredicateNode); + break; // Binding the children will handle everything case SyntaxKind.TypeParameter: return bindTypeParameter(node as TypeParameterDeclaration); case SyntaxKind.Parameter: @@ -2204,17 +2204,6 @@ namespace ts { return bindAnonymousDeclaration(node, SymbolFlags.TypeLiteral, InternalSymbolName.Type); } - function checkTypePredicate(node: TypePredicateNode) { - const { parameterName, type } = node; - if (parameterName && parameterName.kind === SyntaxKind.Identifier) { - checkStrictModeIdentifier(parameterName); - } - if (parameterName && parameterName.kind === SyntaxKind.ThisType) { - seenThisKeyword = true; - } - bind(type); - } - function bindSourceFileIfExternalModule() { setExportContextFlag(file); if (isExternalModule(file)) { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 520b477da0b..587f7eb4837 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -260,7 +260,7 @@ namespace ts { node = getParseTreeNode(node, isJsxOpeningLikeElement); return node ? getAllAttributesTypeFromJsxOpeningLikeElement(node) : undefined; }, - getJsxIntrinsicTagNames, + getJsxIntrinsicTagNamesAt, isOptionalParameter: node => { node = getParseTreeNode(node, isParameter); return node ? isOptionalParameter(node) : false; @@ -299,7 +299,7 @@ namespace ts { resolveName(name, location, meaning, excludeGlobals) { return resolveName(location, escapeLeadingUnderscores(name), meaning, /*nameNotFoundMessage*/ undefined, /*nameArg*/ undefined, /*isUse*/ false, excludeGlobals); }, - getJsxNamespace: () => unescapeLeadingUnderscores(getJsxNamespace()), + getJsxNamespace: n => unescapeLeadingUnderscores(getJsxNamespace(n)), getAccessibleSymbolChain, getTypePredicateOfSignature, resolveExternalModuleSymbol, @@ -416,9 +416,6 @@ namespace ts { let deferredGlobalAsyncIteratorType: GenericType; let deferredGlobalAsyncIterableIteratorType: GenericType; let deferredGlobalTemplateStringsArrayType: ObjectType; - let deferredJsxElementClassType: Type; - let deferredJsxElementType: Type; - let deferredJsxStatelessElementType: Type; let deferredNodes: Node[]; let deferredUnusedIdentifierNodes: Node[]; @@ -544,13 +541,6 @@ namespace ts { let _jsxNamespace: __String; let _jsxFactoryEntity: EntityName; - let _jsxElementPropertiesName: __String; - let _hasComputedJsxElementPropertiesName = false; - let _jsxElementChildrenPropertyName: __String; - let _hasComputedJsxElementChildrenPropertyName = false; - - /** Things we lazy load from the JSX namespace */ - const jsxTypes = createUnderscoreEscapedMap(); const subtypeRelation = createMap(); const assignableRelation = createMap(); @@ -765,7 +755,23 @@ namespace ts { } } - function getJsxNamespace(): __String { + function getJsxNamespace(location: Node | undefined): __String { + if (location) { + const file = getSourceFileOfNode(location); + if (file) { + if (file.localJsxNamespace) { + return file.localJsxNamespace; + } + const jsxPragma = file.pragmas.get("jsx"); + if (jsxPragma) { + const chosenpragma = isArray(jsxPragma) ? jsxPragma[0] : jsxPragma; + file.localJsxFactory = parseIsolatedEntityName(chosenpragma.arguments.factory, languageVersion); + if (file.localJsxFactory) { + return file.localJsxNamespace = getFirstIdentifier(file.localJsxFactory).escapedText; + } + } + } + } if (!_jsxNamespace) { _jsxNamespace = "React" as __String; if (compilerOptions.jsxFactory) { @@ -2750,7 +2756,7 @@ namespace ts { } } - function typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags, writer: EmitTextWriter = createTextWriter("")): string { + function typeToString(type: Type, enclosingDeclaration?: Node, flags: TypeFormatFlags = TypeFormatFlags.AllowUniqueESSymbolType, writer: EmitTextWriter = createTextWriter("")): string { const typeNode = nodeBuilder.typeToTypeNode(type, enclosingDeclaration, toNodeBuilderFlags(flags) | NodeBuilderFlags.IgnoreErrors, writer); Debug.assert(typeNode !== undefined, "should always get typenode"); const options = { removeComments: true }; @@ -2882,6 +2888,9 @@ namespace ts { } if (type.flags & TypeFlags.UniqueESSymbol) { if (!(context.flags & NodeBuilderFlags.AllowUniqueESSymbolType)) { + if (isValueSymbolAccessible(type.symbol, context.enclosingDeclaration)) { + return createTypeQueryNode(symbolToName(type.symbol, context, SymbolFlags.Value, /*expectsIdentifier*/ false)); + } if (context.tracker.reportInaccessibleUniqueSymbolError) { context.tracker.reportInaccessibleUniqueSymbolError(); } @@ -7503,16 +7512,6 @@ namespace ts { return symbol && getTypeOfGlobalSymbol(symbol, arity); } - /** - * Returns a type that is inside a namespace at the global scope, e.g. - * getExportedTypeFromNamespace('JSX', 'Element') returns the JSX.Element type - */ - function getExportedTypeFromNamespace(namespace: __String, name: __String): Type { - const namespaceSymbol = getGlobalSymbol(namespace, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined); - const typeSymbol = namespaceSymbol && getSymbol(namespaceSymbol.exports, name, SymbolFlags.Type); - return typeSymbol && getDeclaredTypeOfSymbol(typeSymbol); - } - /** * Instantiates a global type that is generic with some element type, and returns that instantiation. */ @@ -11167,6 +11166,10 @@ namespace ts { } const result = createSymbol(SymbolFlags.Property | SymbolFlags.Optional, name); result.type = undefinedType; + const associatedKeyType = getLiteralType(unescapeLeadingUnderscores(name)); + if (associatedKeyType.flags & TypeFlags.StringLiteral) { + result.syntheticLiteralTypeOrigin = associatedKeyType as StringLiteralType; + } undefinedProperties.set(name, result); return result; } @@ -11659,7 +11662,7 @@ namespace ts { } } else { - if (!(priority && InferencePriority.NoConstraints && source.flags & (TypeFlags.Intersection | TypeFlags.Instantiable))) { + if (!(priority & InferencePriority.NoConstraints && source.flags & (TypeFlags.Intersection | TypeFlags.Instantiable))) { source = getApparentType(source); } if (source.flags & (TypeFlags.Object | TypeFlags.Intersection)) { @@ -14360,7 +14363,7 @@ namespace ts { function getContextualTypeForChildJsxExpression(node: JsxElement) { 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(); + const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(node)); return attributesType && !isTypeAny(attributesType) && jsxChildrenPropertyName && jsxChildrenPropertyName !== "" ? getTypeOfPropertyOfContextualType(attributesType, jsxChildrenPropertyName) : undefined; } @@ -14514,18 +14517,10 @@ namespace ts { } const isJs = isInJavaScriptFile(node); - return mapType(valueType, isJs ? getJsxSignaturesParameterTypesJs : getJsxSignaturesParameterTypes); + return mapType(valueType, t => getJsxSignaturesParameterTypes(t, isJs, node)); } - function getJsxSignaturesParameterTypes(valueType: Type) { - return getJsxSignaturesParameterTypesInternal(valueType, /*isJs*/ false); - } - - function getJsxSignaturesParameterTypesJs(valueType: Type) { - return getJsxSignaturesParameterTypesInternal(valueType, /*isJs*/ true); - } - - function getJsxSignaturesParameterTypesInternal(valueType: Type, isJs: boolean) { + function getJsxSignaturesParameterTypes(valueType: Type, isJs: boolean, context: Node) { // If the elemType is a string type, we have to return anyType to prevent an error downstream as we will try to find construct or call signature of the type if (valueType.flags & TypeFlags.String) { return anyType; @@ -14535,7 +14530,7 @@ namespace ts { // For example: // var CustomTag: "h1" = "h1"; // Hello World - const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements); + const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements, context); if (intrinsicElementsType !== unknownType) { const stringLiteralTypeName = (valueType).value; const intrinsicProp = getPropertyOfType(intrinsicElementsType, escapeLeadingUnderscores(stringLiteralTypeName)); @@ -14563,24 +14558,24 @@ namespace ts { } } - return getUnionType(map(signatures, ctor ? isJs ? getJsxPropsTypeFromConstructSignatureJs : getJsxPropsTypeFromConstructSignature : getJsxPropsTypeFromCallSignature), UnionReduction.None); + return getUnionType(map(signatures, ctor ? t => getJsxPropsTypeFromConstructSignature(t, isJs, context) : t => getJsxPropsTypeFromCallSignature(t, context)), UnionReduction.None); } - function getJsxPropsTypeFromCallSignature(sig: Signature) { + function getJsxPropsTypeFromCallSignature(sig: Signature, context: Node) { let propsType = getTypeOfFirstParameterOfSignature(sig); - const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes); + const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes, context); if (intrinsicAttribs !== unknownType) { propsType = intersectTypes(intrinsicAttribs, propsType); } return propsType; } - function getJsxPropsTypeFromClassType(hostClassType: Type, isJs: boolean) { + function getJsxPropsTypeFromClassType(hostClassType: Type, isJs: boolean, context: Node) { if (isTypeAny(hostClassType)) { return hostClassType; } - const propsName = getJsxElementPropertiesName(); + const propsName = getJsxElementPropertiesName(getJsxNamespaceAt(context)); if (propsName === undefined) { // There is no type ElementAttributesProperty, return 'any' return anyType; @@ -14603,7 +14598,7 @@ namespace ts { else { // Normal case -- add in IntrinsicClassElements and IntrinsicElements let apparentAttributesType = attributesType; - const intrinsicClassAttribs = getJsxType(JsxNames.IntrinsicClassAttributes); + const intrinsicClassAttribs = getJsxType(JsxNames.IntrinsicClassAttributes, context); if (intrinsicClassAttribs !== unknownType) { const typeParams = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(intrinsicClassAttribs.symbol); apparentAttributesType = intersectTypes( @@ -14614,7 +14609,7 @@ namespace ts { ); } - const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes); + const intrinsicAttribs = getJsxType(JsxNames.IntrinsicAttributes, context); if (intrinsicAttribs !== unknownType) { apparentAttributesType = intersectTypes(intrinsicAttribs, apparentAttributesType); } @@ -14624,20 +14619,12 @@ namespace ts { } } - function getJsxPropsTypeFromConstructSignatureJs(sig: Signature) { - return getJsxPropsTypeFromConstructSignatureInternal(sig, /*isJs*/ true); - } - - function getJsxPropsTypeFromConstructSignature(sig: Signature) { - return getJsxPropsTypeFromConstructSignatureInternal(sig, /*isJs*/ false); - } - - function getJsxPropsTypeFromConstructSignatureInternal(sig: Signature, isJs: boolean) { + function getJsxPropsTypeFromConstructSignature(sig: Signature, isJs: boolean, context: Node) { const hostClassType = getReturnTypeOfSignature(sig); if (hostClassType) { - return getJsxPropsTypeFromClassType(hostClassType, isJs); + return getJsxPropsTypeFromClassType(hostClassType, isJs, context); } - return getJsxPropsTypeFromCallSignature(sig); + return getJsxPropsTypeFromCallSignature(sig, context); } @@ -15092,7 +15079,7 @@ namespace ts { function checkJsxSelfClosingElement(node: JsxSelfClosingElement, checkMode: CheckMode): Type { checkJsxOpeningLikeElementOrOpeningFragment(node, checkMode); - return getJsxGlobalElementType() || anyType; + return getJsxElementTypeAt(node) || anyType; } function checkJsxElement(node: JsxElement, checkMode: CheckMode): Type { @@ -15107,17 +15094,19 @@ namespace ts { checkExpression(node.closingElement.tagName); } - return getJsxGlobalElementType() || anyType; + return getJsxElementTypeAt(node) || anyType; } function checkJsxFragment(node: JsxFragment, checkMode: CheckMode): Type { checkJsxOpeningLikeElementOrOpeningFragment(node.openingFragment, checkMode); - if (compilerOptions.jsx === JsxEmit.React && compilerOptions.jsxFactory) { - error(node, Diagnostics.JSX_fragment_is_not_supported_when_using_jsxFactory); + if (compilerOptions.jsx === JsxEmit.React && (compilerOptions.jsxFactory || getSourceFileOfNode(node).pragmas.has("jsx"))) { + error(node, compilerOptions.jsxFactory + ? Diagnostics.JSX_fragment_is_not_supported_when_using_jsxFactory + : Diagnostics.JSX_fragment_is_not_supported_when_using_an_inline_JSX_factory_pragma); } - return getJsxGlobalElementType() || anyType; + return getJsxElementTypeAt(node) || anyType; } /** @@ -15166,7 +15155,7 @@ namespace ts { let hasSpreadAnyType = false; let typeToIntersect: Type; let explicitlySpecifyChildrenAttribute = false; - const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(); + const jsxChildrenPropertyName = getJsxElementChildrenPropertyName(getJsxNamespaceAt(openingLikeElement)); for (const attributeDecl of attributes.properties) { const member = attributeDecl.symbol; @@ -15282,12 +15271,11 @@ namespace ts { return createJsxAttributesTypeFromAttributesProperty(node.parent, checkMode); } - function getJsxType(name: __String) { - let jsxType = jsxTypes.get(name); - if (jsxType === undefined) { - jsxTypes.set(name, jsxType = getExportedTypeFromNamespace(JsxNames.JSX, name) || unknownType); - } - return jsxType; + function getJsxType(name: __String, location: Node) { + const namespace = getJsxNamespaceAt(location); + const exports = namespace && getExportsOfSymbol(namespace); + const typeSymbol = exports && getSymbol(exports, name, SymbolFlags.Type); + return typeSymbol ? getDeclaredTypeOfSymbol(typeSymbol) : unknownType; } /** @@ -15299,7 +15287,7 @@ namespace ts { function getIntrinsicTagSymbol(node: JsxOpeningLikeElement | JsxClosingElement): Symbol { const links = getNodeLinks(node); if (!links.resolvedSymbol) { - const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements); + const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements, node); if (intrinsicElementsType !== unknownType) { // Property case if (!isIdentifier(node.tagName)) throw Debug.fail(); @@ -15371,6 +15359,19 @@ namespace ts { return getUnionType(map(instantiatedSignatures, getReturnTypeOfSignature), UnionReduction.Subtype); } + function getJsxNamespaceAt(location: Node) { + const namespaceName = getJsxNamespace(location); + const resolvedNamespace = resolveName(location, namespaceName, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined, namespaceName, /*isUse*/ false); + if (resolvedNamespace) { + const candidate = getSymbol(getExportsOfSymbol(resolveSymbol(resolvedNamespace)), JsxNames.JSX, SymbolFlags.Namespace); + if (candidate) { + return candidate; + } + } + // JSX global fallback + return getGlobalSymbol(JsxNames.JSX, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined); + } + /** * Look into JSX namespace and then look for container with matching name as nameOfAttribPropContainer. * Get a single property from that container if existed. Report an error if there are more than one property. @@ -15378,9 +15379,7 @@ namespace ts { * @param nameOfAttribPropContainer a string of value JsxNames.ElementAttributesPropertyNameContainer or JsxNames.ElementChildrenAttributeNameContainer * if other string is given or the container doesn't exist, return undefined. */ - function getNameFromJsxElementAttributesContainer(nameOfAttribPropContainer: __String): __String { - // JSX - const jsxNamespace = getGlobalSymbol(JsxNames.JSX, SymbolFlags.Namespace, /*diagnosticMessage*/ undefined); + function getNameFromJsxElementAttributesContainer(nameOfAttribPropContainer: __String, jsxNamespace: Symbol): __String { // JSX.ElementAttributesProperty | JSX.ElementChildrenAttribute [symbol] const jsxElementAttribPropInterfaceSym = jsxNamespace && getSymbol(jsxNamespace.exports, nameOfAttribPropContainer, SymbolFlags.Type); // JSX.ElementAttributesProperty | JSX.ElementChildrenAttribute [type] @@ -15410,22 +15409,12 @@ namespace ts { /// non-intrinsic elements' attributes type is 'any'), /// or '' if it has 0 properties (which means every /// non-intrinsic elements' attributes type is the element instance type) - function getJsxElementPropertiesName() { - if (!_hasComputedJsxElementPropertiesName) { - _hasComputedJsxElementPropertiesName = true; - _jsxElementPropertiesName = getNameFromJsxElementAttributesContainer(JsxNames.ElementAttributesPropertyNameContainer); - } - - return _jsxElementPropertiesName; + function getJsxElementPropertiesName(jsxNamespace: Symbol) { + return getNameFromJsxElementAttributesContainer(JsxNames.ElementAttributesPropertyNameContainer, jsxNamespace); } - function getJsxElementChildrenPropertyName(): __String { - if (!_hasComputedJsxElementChildrenPropertyName) { - _hasComputedJsxElementChildrenPropertyName = true; - _jsxElementChildrenPropertyName = getNameFromJsxElementAttributesContainer(JsxNames.ElementChildrenAttributeNameContainer); - } - - return _jsxElementChildrenPropertyName; + function getJsxElementChildrenPropertyName(jsxNamespace: Symbol): __String { + return getNameFromJsxElementAttributesContainer(JsxNames.ElementChildrenAttributeNameContainer, jsxNamespace); } function getApparentTypeOfJsxPropsType(propsType: Type): Type { @@ -15455,7 +15444,7 @@ namespace ts { function defaultTryGetJsxStatelessFunctionAttributesType(openingLikeElement: JsxOpeningLikeElement, elementType: Type, elemInstanceType: Type, elementClassType?: Type): Type { Debug.assert(!(elementType.flags & TypeFlags.Union)); if (!elementClassType || !isTypeAssignableTo(elemInstanceType, elementClassType)) { - const jsxStatelessElementType = getJsxGlobalStatelessElementType(); + const jsxStatelessElementType = getJsxStatelessElementTypeAt(openingLikeElement); if (jsxStatelessElementType) { // We don't call getResolvedSignature here because we have already resolve the type of JSX Element. const callSignature = getResolvedJsxStatelessFunctionSignature(openingLikeElement, elementType, /*candidatesOutArray*/ undefined); @@ -15465,7 +15454,7 @@ namespace ts { paramType = getApparentTypeOfJsxPropsType(paramType); if (callReturnType && isTypeAssignableTo(callReturnType, jsxStatelessElementType)) { // Intersect in JSX.IntrinsicAttributes if it exists - const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes); + const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes, openingLikeElement); if (intrinsicAttributes !== unknownType) { paramType = intersectTypes(intrinsicAttributes, paramType); } @@ -15491,7 +15480,7 @@ namespace ts { Debug.assert(!(elementType.flags & TypeFlags.Union)); if (!elementClassType || !isTypeAssignableTo(elemInstanceType, elementClassType)) { // Is this is a stateless function component? See if its single signature's return type is assignable to the JSX Element Type - const jsxStatelessElementType = getJsxGlobalStatelessElementType(); + const jsxStatelessElementType = getJsxStatelessElementTypeAt(openingLikeElement); if (jsxStatelessElementType) { // We don't call getResolvedSignature because here we have already resolve the type of JSX Element. const candidatesOutArray: Signature[] = []; @@ -15524,7 +15513,7 @@ namespace ts { result = allMatchingAttributesType; } // Intersect in JSX.IntrinsicAttributes if it exists - const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes); + const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes, openingLikeElement); if (intrinsicAttributes !== unknownType) { result = intersectTypes(intrinsicAttributes, result); } @@ -15573,7 +15562,7 @@ namespace ts { // For example: // var CustomTag: "h1" = "h1"; // Hello World - const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements); + const intrinsicElementsType = getJsxType(JsxNames.IntrinsicElements, openingLikeElement); if (intrinsicElementsType !== unknownType) { const stringLiteralTypeName = (elementType).value; const intrinsicProp = getPropertyOfType(intrinsicElementsType, escapeLeadingUnderscores(stringLiteralTypeName)); @@ -15608,7 +15597,7 @@ namespace ts { checkTypeRelatedTo(elemInstanceType, elementClassType, assignableRelation, openingLikeElement, Diagnostics.JSX_element_type_0_is_not_a_constructor_function_for_JSX_elements); } - return getJsxPropsTypeFromClassType(elemInstanceType, isInJavaScriptFile(openingLikeElement)); + return getJsxPropsTypeFromClassType(elemInstanceType, isInJavaScriptFile(openingLikeElement), openingLikeElement); } /** @@ -15641,7 +15630,7 @@ namespace ts { * @param shouldIncludeAllStatelessAttributesType a boolean value used by language service to get all possible attributes type from an overload stateless function component */ function getCustomJsxElementAttributesType(node: JsxOpeningLikeElement, shouldIncludeAllStatelessAttributesType: boolean): Type { - return resolveCustomJsxElementAttributesType(node, shouldIncludeAllStatelessAttributesType, checkExpression(node.tagName), getJsxGlobalElementClassType()); + return resolveCustomJsxElementAttributesType(node, shouldIncludeAllStatelessAttributesType, checkExpression(node.tagName), getJsxElementClassTypeAt(node)); } /** @@ -15685,35 +15674,28 @@ namespace ts { return prop || unknownSymbol; } - function getJsxGlobalElementClassType(): Type { - if (!deferredJsxElementClassType) { - deferredJsxElementClassType = getExportedTypeFromNamespace(JsxNames.JSX, JsxNames.ElementClass); - } - return deferredJsxElementClassType; + function getJsxElementClassTypeAt(location: Node): Type { + const type = getJsxType(JsxNames.ElementClass, location); + if (type === unknownType) return undefined; + return type; } - function getJsxGlobalElementType(): Type { - if (!deferredJsxElementType) { - deferredJsxElementType = getExportedTypeFromNamespace(JsxNames.JSX, JsxNames.Element); - } - return deferredJsxElementType; + function getJsxElementTypeAt(location: Node): Type { + return getJsxType(JsxNames.Element, location); } - function getJsxGlobalStatelessElementType(): Type { - if (!deferredJsxStatelessElementType) { - const jsxElementType = getJsxGlobalElementType(); - if (jsxElementType) { - deferredJsxStatelessElementType = getUnionType([jsxElementType, nullType]); - } + function getJsxStatelessElementTypeAt(location: Node): Type { + const jsxElementType = getJsxElementTypeAt(location); + if (jsxElementType) { + return getUnionType([jsxElementType, nullType]); } - return deferredJsxStatelessElementType; } /** * Returns all the properties of the Jsx.IntrinsicElements interface */ - function getJsxIntrinsicTagNames(): Symbol[] { - const intrinsics = getJsxType(JsxNames.IntrinsicElements); + function getJsxIntrinsicTagNamesAt(location: Node): Symbol[] { + const intrinsics = getJsxType(JsxNames.IntrinsicElements, location); return intrinsics ? getPropertiesOfType(intrinsics) : emptyArray; } @@ -15723,7 +15705,7 @@ namespace ts { error(errorNode, Diagnostics.Cannot_use_JSX_unless_the_jsx_flag_is_provided); } - if (getJsxGlobalElementType() === undefined) { + if (getJsxElementTypeAt(errorNode) === undefined) { if (noImplicitAny) { error(errorNode, Diagnostics.JSX_element_implicitly_has_type_any_because_the_global_type_JSX_Element_does_not_exist); } @@ -15740,7 +15722,7 @@ namespace ts { // The reactNamespace/jsxFactory's root symbol should be marked as 'used' so we don't incorrectly elide its import. // And if there is no reactNamespace/jsxFactory's symbol in scope when targeting React emit, we should issue an error. const reactRefErr = diagnostics && compilerOptions.jsx === JsxEmit.React ? Diagnostics.Cannot_find_name_0 : undefined; - const reactNamespace = getJsxNamespace(); + const reactNamespace = getJsxNamespace(node); const reactLocation = isNodeOpeningLikeElement ? (node).tagName : node; const reactSym = resolveName(reactLocation, reactNamespace, SymbolFlags.Value, reactRefErr, reactNamespace, /*isUse*/ true); if (reactSym) { @@ -15823,7 +15805,7 @@ namespace ts { // If the targetAttributesType is an emptyObjectType, indicating that there is no property named 'props' on this instance type. // but there exists a sourceAttributesType, we need to explicitly give an error as normal assignability check allow excess properties and will pass. if (targetAttributesType === emptyObjectType && (isTypeAny(sourceAttributesType) || getPropertiesOfType(sourceAttributesType).length > 0)) { - error(openingLikeElement, Diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, unescapeLeadingUnderscores(getJsxElementPropertiesName())); + error(openingLikeElement, Diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, unescapeLeadingUnderscores(getJsxElementPropertiesName(getJsxNamespaceAt(openingLikeElement)))); } else { // Check if sourceAttributesType assignable to targetAttributesType though this check will allow excess properties @@ -25587,7 +25569,7 @@ namespace ts { return !!(symbol && getCheckFlags(symbol) & CheckFlags.Late); }, writeLiteralConstValue, - getJsxFactoryEntity: () => _jsxFactoryEntity + getJsxFactoryEntity: location => location ? (getJsxNamespace(location), (getSourceFileOfNode(location).localJsxFactory || _jsxFactoryEntity)) : _jsxFactoryEntity }; // defined here to avoid outer scope pollution diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts index a9b3568bfe6..43c635db2f2 100644 --- a/src/compiler/declarationEmitter.ts +++ b/src/compiler/declarationEmitter.ts @@ -608,7 +608,12 @@ namespace ts { "?"); } write(": "); - emitType(node.type); + if (node.type) { + emitType(node.type); + } + else { + write("any"); + } write(";"); writeLine(); decreaseIndent(); diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 9801da54a5f..ba69e4db966 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2602,7 +2602,7 @@ "code": 4083 }, "Conflicting definitions for '{0}' found at '{1}' and '{2}'. Consider installing a specific version of this library to resolve the conflict.": { - "category": "Message", + "category": "Error", "code": 4090 }, "Parameter '{0}' of index signature from exported interface has or is using name '{1}' from private module '{2}'.": { @@ -3296,7 +3296,7 @@ "category": "Message", "code": 6146 }, - "Resolution for module '{0}' was found in cache.": { + "Resolution for module '{0}' was found in cache from location '{1}'.": { "category": "Message", "code": 6147 }, @@ -3788,6 +3788,10 @@ "category": "Error", "code": 17016 }, + "JSX fragment is not supported when using an inline JSX factory pragma": { + "category": "Error", + "code": 17017 + }, "Circularity detected while resolving configuration: {0}": { "category": "Error", @@ -3806,6 +3810,11 @@ "code": 18003 }, + "File is a CommonJS module; it may be converted to an ES6 module.": { + "category": "Suggestion", + "code": 80001 + }, + "Add missing 'super()' call": { "category": "Message", "code": 90001 diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 92d353aeb0e..bb00a967336 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -2375,6 +2375,9 @@ namespace ts { if (node.resolvedTypeReferenceDirectiveNames !== undefined) updated.resolvedTypeReferenceDirectiveNames = node.resolvedTypeReferenceDirectiveNames; if (node.imports !== undefined) updated.imports = node.imports; if (node.moduleAugmentations !== undefined) updated.moduleAugmentations = node.moduleAugmentations; + if (node.pragmas !== undefined) updated.pragmas = node.pragmas; + if (node.localJsxFactory !== undefined) updated.localJsxFactory = node.localJsxFactory; + if (node.localJsxNamespace !== undefined) updated.localJsxNamespace = node.localJsxNamespace; return updateNode(updated, node); } diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index ddb0f5cbb5d..de59e640192 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -335,8 +335,20 @@ namespace ts { } export function createModuleResolutionCache(currentDirectory: string, getCanonicalFileName: (s: string) => string): ModuleResolutionCache { - const directoryToModuleNameMap = createMap>(); - const moduleNameToDirectoryMap = createMap(); + return createModuleResolutionCacheWithMaps( + createMap>(), + createMap(), + currentDirectory, + getCanonicalFileName + ); + } + + /*@internal*/ + export function createModuleResolutionCacheWithMaps( + directoryToModuleNameMap: Map>, + moduleNameToDirectoryMap: Map, + currentDirectory: string, + getCanonicalFileName: GetCanonicalFileName): ModuleResolutionCache { return { getOrCreateCacheForDirectory, getOrCreateCacheForModuleName }; @@ -445,7 +457,7 @@ namespace ts { if (result) { if (traceEnabled) { - trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache, moduleName); + trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, moduleName, containingDirectory); } } else { @@ -1188,7 +1200,7 @@ namespace ts { const result = cache && cache.get(containingDirectory); if (result) { if (traceEnabled) { - trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache, moduleName); + trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, moduleName, containingDirectory); } return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, extension: result.resolvedModule.extension, packageId: result.resolvedModule.packageId } }; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 70ddb7b791d..b350af01bb0 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -769,7 +769,9 @@ namespace ts { // Prime the scanner. nextToken(); - processReferenceComments(sourceFile); + // A member of ReadonlyArray isn't assignable to a member of T[] (and prevents a direct cast) - but this is where we set up those members so they can be readonly in the future + processCommentPragmas(sourceFile as {} as PragmaContext, sourceText); + processPragmasIntoFields(sourceFile as {} as PragmaContext, reportPragmaDiagnostic); sourceFile.statements = parseList(ParsingContext.SourceElements, parseStatement); Debug.assert(token() === SyntaxKind.EndOfFileToken); @@ -787,6 +789,10 @@ namespace ts { } return sourceFile; + + function reportPragmaDiagnostic(pos: number, end: number, diagnostic: DiagnosticMessage) { + parseDiagnostics.push(createFileDiagnostic(sourceFile, pos, end, diagnostic)); + } } function addJSDocComment(node: T): T { @@ -6084,94 +6090,6 @@ namespace ts { return finishNode(node); } - function processReferenceComments(sourceFile: SourceFile): void { - const triviaScanner = createScanner(sourceFile.languageVersion, /*skipTrivia*/ false, LanguageVariant.Standard, sourceText); - const referencedFiles: FileReference[] = []; - const typeReferenceDirectives: FileReference[] = []; - const amdDependencies: { path: string; name: string }[] = []; - let amdModuleName: string; - let checkJsDirective: CheckJsDirective = undefined; - - // Keep scanning all the leading trivia in the file until we get to something that - // isn't trivia. Any single line comment will be analyzed to see if it is a - // reference comment. - while (true) { - const kind = triviaScanner.scan(); - if (kind !== SyntaxKind.SingleLineCommentTrivia) { - if (isTrivia(kind)) { - continue; - } - else { - break; - } - } - - const range = { - kind: triviaScanner.getToken(), - pos: triviaScanner.getTokenPos(), - end: triviaScanner.getTextPos(), - }; - - const comment = sourceText.substring(range.pos, range.end); - const referencePathMatchResult = getFileReferenceFromReferencePath(comment, range); - if (referencePathMatchResult) { - const fileReference = referencePathMatchResult.fileReference; - sourceFile.hasNoDefaultLib = referencePathMatchResult.isNoDefaultLib; - const diagnosticMessage = referencePathMatchResult.diagnosticMessage; - if (fileReference) { - if (referencePathMatchResult.isTypeReferenceDirective) { - typeReferenceDirectives.push(fileReference); - } - else { - referencedFiles.push(fileReference); - } - } - if (diagnosticMessage) { - parseDiagnostics.push(createFileDiagnostic(sourceFile, range.pos, range.end - range.pos, diagnosticMessage)); - } - } - else { - const amdModuleNameRegEx = /^\/\/\/\s* hasModifier(node, ModifierFlags.Export) @@ -7552,4 +7470,225 @@ namespace ts { function isDeclarationFileName(fileName: string): boolean { return fileExtensionIs(fileName, Extension.Dts); } + + /*@internal*/ + export interface PragmaContext { + languageVersion: ScriptTarget; + pragmas?: PragmaMap; + checkJsDirective?: CheckJsDirective; + referencedFiles: FileReference[]; + typeReferenceDirectives: FileReference[]; + amdDependencies: AmdDependency[]; + hasNoDefaultLib?: boolean; + moduleName?: string; + } + + /*@internal*/ + export function processCommentPragmas(context: PragmaContext, sourceText: string): void { + const triviaScanner = createScanner(context.languageVersion, /*skipTrivia*/ false, LanguageVariant.Standard, sourceText); + const pragmas: PragmaPsuedoMapEntry[] = []; + + // Keep scanning all the leading trivia in the file until we get to something that + // isn't trivia. Any single line comment will be analyzed to see if it is a + // reference comment. + while (true) { + const kind = triviaScanner.scan(); + if (!isTrivia(kind)) { + break; + } + + const range = { + kind: triviaScanner.getToken(), + pos: triviaScanner.getTokenPos(), + end: triviaScanner.getTextPos(), + }; + + const comment = sourceText.substring(range.pos, range.end); + extractPragmas(pragmas, range, comment); + } + + context.pragmas = createMap() as PragmaMap; + for (const pragma of pragmas) { + if (context.pragmas.has(pragma.name)) { + const currentValue = context.pragmas.get(pragma.name); + if (currentValue instanceof Array) { + currentValue.push(pragma.args); + } + else { + context.pragmas.set(pragma.name, [currentValue, pragma.args]); + } + continue; + } + context.pragmas.set(pragma.name, pragma.args); + } + } + + /*@internal*/ + type PragmaDiagnosticReporter = (pos: number, length: number, message: DiagnosticMessage) => void; + + /*@internal*/ + export function processPragmasIntoFields(context: PragmaContext, reportDiagnostic: PragmaDiagnosticReporter): void { + context.checkJsDirective = undefined; + context.referencedFiles = []; + context.typeReferenceDirectives = []; + context.amdDependencies = []; + context.hasNoDefaultLib = false; + context.pragmas.forEach((entryOrList, key) => { + // TODO: The below should be strongly type-guarded and not need casts/explicit annotations, since entryOrList is related to + // key and key is constrained to a union; but it's not (see GH#21483 for at least partial fix) :( + switch (key) { + case "reference": { + const referencedFiles = context.referencedFiles; + const typeReferenceDirectives = context.typeReferenceDirectives; + forEach(toArray(entryOrList), (arg: PragmaPsuedoMap["reference"]) => { + 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 (arg.arguments.path) { + referencedFiles.push({ pos: arg.arguments.path.pos, end: arg.arguments.path.end, fileName: arg.arguments.path.value }); + } + else { + reportDiagnostic(arg.range.pos, arg.range.end - arg.range.pos, Diagnostics.Invalid_reference_directive_syntax); + } + }); + break; + } + case "amd-dependency": { + context.amdDependencies = map( + toArray(entryOrList), + ({ arguments: { name, path } }: PragmaPsuedoMap["amd-dependency"]) => ({ name, path }) + ); + break; + } + case "amd-module": { + if (entryOrList instanceof Array) { + for (const entry of entryOrList) { + if (context.moduleName) { + // TODO: It's probably fine to issue this diagnostic on all instances of the pragma + reportDiagnostic(entry.range.pos, entry.range.end - entry.range.pos, Diagnostics.An_AMD_module_cannot_have_multiple_name_assignments); + } + context.moduleName = (entry as PragmaPsuedoMap["amd-module"]).arguments.name; + } + } + else { + context.moduleName = (entryOrList as PragmaPsuedoMap["amd-module"]).arguments.name; + } + break; + } + case "ts-nocheck": + case "ts-check": { + // _last_ of either nocheck or check in a file is the "winner" + forEach(toArray(entryOrList), entry => { + if (!context.checkJsDirective || entry.range.pos > context.checkJsDirective.pos) { + context.checkJsDirective = { + enabled: key === "ts-check", + end: entry.range.end, + pos: entry.range.pos + }; + } + }); + break; + } + case "jsx": return; // Accessed directly + default: Debug.fail("Unhandled pragma kind"); // Can this be made into an assertNever in the future? + } + }); + } + + const namedArgRegExCache = createMap(); + function getNamedArgRegEx(name: string) { + if (namedArgRegExCache.has(name)) { + return namedArgRegExCache.get(name); + } + const result = new RegExp(`(\\s${name}\\s*=\\s*)('|")(.+?)\\2`, "im"); + namedArgRegExCache.set(name, result); + return result; + } + + const tripleSlashXMLCommentStartRegEx = /^\/\/\/\s*<(\S+)\s.*?\/>/im; + const singleLinePragmaRegEx = /^\/\/\/?\s*@(\S+)\s*(.*)\s*$/im; + function extractPragmas(pragmas: PragmaPsuedoMapEntry[], range: CommentRange, text: string) { + const tripleSlash = tripleSlashXMLCommentStartRegEx.exec(text); + if (tripleSlash) { + const name = tripleSlash[1].toLowerCase() as keyof PragmaPsuedoMap; // Technically unsafe cast, but we do it so the below check to make it safe typechecks + const pragma = commentPragmas[name] as PragmaDefinition; + if (!pragma || !(pragma.kind & PragmaKindFlags.TripleSlashXML)) { + return; + } + if (pragma.args) { + const argument: {[index: string]: string | {value: string, pos: number, end: number}} = {}; + for (const arg of pragma.args) { + const matcher = getNamedArgRegEx(arg.name); + const matchResult = matcher.exec(text); + if (!matchResult && !arg.optional) { + return; // Missing required argument, don't parse + } + else if (matchResult) { + if (arg.captureSpan) { + const startPos = range.pos + matchResult.index + matchResult[1].length + matchResult[2].length; + argument[arg.name] = { + value: matchResult[3], + pos: startPos, + end: startPos + matchResult[3].length + }; + } + else { + argument[arg.name] = matchResult[3]; + } + } + } + pragmas.push({ name, args: { arguments: argument, range } } as PragmaPsuedoMapEntry); + } + else { + pragmas.push({ name, args: { arguments: {}, range } } as PragmaPsuedoMapEntry); + } + return; + } + + const singleLine = singleLinePragmaRegEx.exec(text); + if (singleLine) { + return addPragmaForMatch(pragmas, range, PragmaKindFlags.SingleLine, singleLine); + } + + const multiLinePragmaRegEx = /\s*@(\S+)\s*(.*)\s*$/gim; // Defined inline since it uses the "g" flag, which keeps a persistent index (for iterating) + let multiLineMatch: RegExpExecArray; + while (multiLineMatch = multiLinePragmaRegEx.exec(text)) { + addPragmaForMatch(pragmas, range, PragmaKindFlags.MultiLine, multiLineMatch); + } + } + + function addPragmaForMatch(pragmas: PragmaPsuedoMapEntry[], range: CommentRange, kind: PragmaKindFlags, match: RegExpExecArray) { + if (!match) return; + const name = match[1].toLowerCase() as keyof PragmaPsuedoMap; // Technically unsafe cast, but we do it so they below check to make it safe typechecks + const pragma = commentPragmas[name] as PragmaDefinition; + if (!pragma || !(pragma.kind & kind)) { + return; + } + const args = match[2]; // Split on spaces and match up positionally with definition + const argument = getNamedPragmaArguments(pragma, args); + if (argument === "fail") return; // Missing required argument, fail to parse it + pragmas.push({ name, args: { arguments: argument, range } } as PragmaPsuedoMapEntry); + return; + } + + function getNamedPragmaArguments(pragma: PragmaDefinition, text: string | undefined): {[index: string]: string} | "fail" { + if (!text) return {}; + if (!pragma.args) return {}; + const args = text.split(/\s+/); + const argMap: {[index: string]: string} = {}; + for (let i = 0; i < pragma.args.length; i++) { + const argument = pragma.args[i]; + if (!args[i] && !argument.optional) { + return "fail"; + } + if (argument.captureSpan) { + return Debug.fail("Capture spans not yet implemented for non-xml pragmas"); + } + argMap[argument.name] = args[i]; + } + return argMap; + } } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 1ce672a6a75..aff5154abe0 100755 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -227,8 +227,7 @@ namespace ts { } export function formatDiagnostic(diagnostic: Diagnostic, host: FormatDiagnosticsHost): string { - const category = DiagnosticCategory[diagnostic.category].toLowerCase(); - const errorMessage = `${category} TS${diagnostic.code}: ${flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine())}${host.getNewLine()}`; + const errorMessage = `${diagnosticCategoryName(diagnostic)} TS${diagnostic.code}: ${flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine())}${host.getNewLine()}`; if (diagnostic.file) { const { line, character } = getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start); @@ -254,8 +253,9 @@ namespace ts { const ellipsis = "..."; function getCategoryFormat(category: DiagnosticCategory): string { switch (category) { - case DiagnosticCategory.Warning: return ForegroundColorEscapeSequences.Yellow; case DiagnosticCategory.Error: return ForegroundColorEscapeSequences.Red; + case DiagnosticCategory.Warning: return ForegroundColorEscapeSequences.Yellow; + case DiagnosticCategory.Suggestion: return Debug.fail("Should never get an Info diagnostic on the command line."); case DiagnosticCategory.Message: return ForegroundColorEscapeSequences.Blue; } } @@ -337,9 +337,7 @@ namespace ts { output += " - "; } - const categoryColor = getCategoryFormat(diagnostic.category); - const category = DiagnosticCategory[diagnostic.category].toLowerCase(); - output += formatColorAndReset(category, categoryColor); + output += formatColorAndReset(diagnosticCategoryName(diagnostic), getCategoryFormat(diagnostic.category)); output += formatColorAndReset(` TS${ diagnostic.code }: `, ForegroundColorEscapeSequences.Grey); output += flattenDiagnosticMessageText(diagnostic.messageText, host.getNewLine()); diff --git a/src/compiler/resolutionCache.ts b/src/compiler/resolutionCache.ts index e907d2d62b7..01c7bc59fdd 100644 --- a/src/compiler/resolutionCache.ts +++ b/src/compiler/resolutionCache.ts @@ -28,6 +28,7 @@ namespace ts { interface ResolutionWithFailedLookupLocations { readonly failedLookupLocations: ReadonlyArray; isInvalidated?: boolean; + refCount?: number; } interface ResolutionWithResolvedFileName { @@ -42,6 +43,7 @@ namespace ts { export interface ResolutionCacheHost extends ModuleResolutionHost { toPath(fileName: string): Path; + getCanonicalFileName: GetCanonicalFileName; getCompilationSettings(): CompilerOptions; watchDirectoryOfFailedLookupLocation(directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags): FileWatcher; onInvalidatedResolution(): void; @@ -78,18 +80,25 @@ namespace ts { let filesWithInvalidatedResolutions: Map | undefined; let allFilesHaveInvalidatedResolution = false; + const getCurrentDirectory = memoize(() => resolutionHost.getCurrentDirectory()); + const cachedDirectoryStructureHost = resolutionHost.getCachedDirectoryStructureHost(); + // The resolvedModuleNames and resolvedTypeReferenceDirectives are the cache of resolutions per file. // The key in the map is source file's path. // The values are Map of resolutions with key being name lookedup. const resolvedModuleNames = createMap>(); const perDirectoryResolvedModuleNames = createMap>(); + const nonRelaticeModuleNameCache = createMap(); + const moduleResolutionCache = createModuleResolutionCacheWithMaps( + perDirectoryResolvedModuleNames, + nonRelaticeModuleNameCache, + getCurrentDirectory(), + resolutionHost.getCanonicalFileName + ); const resolvedTypeReferenceDirectives = createMap>(); const perDirectoryResolvedTypeReferenceDirectives = createMap>(); - const getCurrentDirectory = memoize(() => resolutionHost.getCurrentDirectory()); - const cachedDirectoryStructureHost = resolutionHost.getCachedDirectoryStructureHost(); - /** * These are the extensions that failed lookup files will have by default, * any other extension of failed lookup will be store that path in custom failed lookup path @@ -173,6 +182,7 @@ namespace ts { function clearPerDirectoryResolutions() { perDirectoryResolvedModuleNames.clear(); + nonRelaticeModuleNameCache.clear(); perDirectoryResolvedTypeReferenceDirectives.clear(); } @@ -189,7 +199,7 @@ namespace ts { } function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations { - const primaryResult = ts.resolveModuleName(moduleName, containingFile, compilerOptions, host); + const primaryResult = ts.resolveModuleName(moduleName, containingFile, compilerOptions, host, moduleResolutionCache); // return result immediately only if global cache support is not enabled or if it is .ts, .tsx or .d.ts if (!resolutionHost.getGlobalCache) { return primaryResult; @@ -248,17 +258,11 @@ namespace ts { perDirectoryResolution.set(name, resolution); } resolutionsInFile.set(name, resolution); - if (resolution.failedLookupLocations) { - if (existingResolution && existingResolution.failedLookupLocations) { - watchAndStopWatchDiffFailedLookupLocations(resolution, existingResolution); - } - else { - watchFailedLookupLocationOfResolution(resolution, 0); - } - } - else if (existingResolution) { + watchFailedLookupLocationOfResolution(resolution); + if (existingResolution) { stopWatchFailedLookupLocationOfResolution(existingResolution); } + if (logChanges && filesWithChangedSetOfUnresolvedImports && !resolutionIsEqualTo(existingResolution, resolution)) { filesWithChangedSetOfUnresolvedImports.push(path); // reset log changes to avoid recording the same file multiple times @@ -390,80 +394,98 @@ namespace ts { return fileExtensionIsOneOf(path, failedLookupDefaultExtensions); } - function watchAndStopWatchDiffFailedLookupLocations(resolution: ResolutionWithFailedLookupLocations, existingResolution: ResolutionWithFailedLookupLocations) { - const failedLookupLocations = resolution.failedLookupLocations; - const existingFailedLookupLocations = existingResolution.failedLookupLocations; - for (let index = 0; index < failedLookupLocations.length; index++) { - if (index === existingFailedLookupLocations.length) { - // Additional failed lookup locations, watch from this index - watchFailedLookupLocationOfResolution(resolution, index); - return; - } - else if (failedLookupLocations[index] !== existingFailedLookupLocations[index]) { - // Different failed lookup locations, - // Watch new resolution failed lookup locations from this index and - // stop watching existing resolutions from this index - watchFailedLookupLocationOfResolution(resolution, index); - stopWatchFailedLookupLocationOfResolutionFrom(existingResolution, index); - return; + function watchFailedLookupLocationOfResolution(resolution: ResolutionWithFailedLookupLocations) { + // No need to set the resolution refCount + if (!resolution.failedLookupLocations || !resolution.failedLookupLocations.length) { + return; + } + + if (resolution.refCount !== undefined) { + resolution.refCount++; + return; + } + + resolution.refCount = 1; + const { failedLookupLocations } = resolution; + let setAtRoot = false; + for (const failedLookupLocation of failedLookupLocations) { + const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation); + const { dir, dirPath, ignore } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath); + if (!ignore) { + // If the failed lookup location path is not one of the supported extensions, + // store it in the custom path + if (!isPathWithDefaultFailedLookupExtension(failedLookupLocationPath)) { + const refCount = customFailedLookupPaths.get(failedLookupLocationPath) || 0; + customFailedLookupPaths.set(failedLookupLocationPath, refCount + 1); + } + if (dirPath === rootPath) { + setAtRoot = true; + } + else { + setDirectoryWatcher(dir, dirPath); + } } } - // All new failed lookup locations are already watched (and are same), - // Stop watching failed lookup locations of existing resolution after failed lookup locations length - stopWatchFailedLookupLocationOfResolutionFrom(existingResolution, failedLookupLocations.length); + if (setAtRoot) { + setDirectoryWatcher(rootDir, rootPath); + } } - function watchFailedLookupLocationOfResolution({ failedLookupLocations }: ResolutionWithFailedLookupLocations, startIndex: number) { - for (let i = startIndex; i < failedLookupLocations.length; i++) { - const failedLookupLocation = failedLookupLocations[i]; - const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation); - // If the failed lookup location path is not one of the supported extensions, - // store it in the custom path - if (!isPathWithDefaultFailedLookupExtension(failedLookupLocationPath)) { - const refCount = customFailedLookupPaths.get(failedLookupLocationPath) || 0; - customFailedLookupPaths.set(failedLookupLocationPath, refCount + 1); - } - const { dir, dirPath, ignore } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath); - if (!ignore) { - const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath); - if (dirWatcher) { - dirWatcher.refCount++; - } - else { - directoryWatchesOfFailedLookups.set(dirPath, { watcher: createDirectoryWatcher(dir, dirPath), refCount: 1 }); - } - } + function setDirectoryWatcher(dir: string, dirPath: Path) { + const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath); + if (dirWatcher) { + dirWatcher.refCount++; + } + else { + directoryWatchesOfFailedLookups.set(dirPath, { watcher: createDirectoryWatcher(dir, dirPath), refCount: 1 }); } } function stopWatchFailedLookupLocationOfResolution(resolution: ResolutionWithFailedLookupLocations) { - if (resolution.failedLookupLocations) { - stopWatchFailedLookupLocationOfResolutionFrom(resolution, 0); + if (!resolution.failedLookupLocations || !resolution.failedLookupLocations.length) { + return; + } + + resolution.refCount!--; + if (resolution.refCount) { + return; + } + + const { failedLookupLocations } = resolution; + let removeAtRoot = false; + for (const failedLookupLocation of failedLookupLocations) { + const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation); + const { dirPath, ignore } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath); + if (!ignore) { + const refCount = customFailedLookupPaths.get(failedLookupLocationPath); + if (refCount) { + if (refCount === 1) { + customFailedLookupPaths.delete(failedLookupLocationPath); + } + else { + Debug.assert(refCount > 1); + customFailedLookupPaths.set(failedLookupLocationPath, refCount - 1); + } + } + + if (dirPath === rootPath) { + removeAtRoot = true; + } + else { + removeDirectoryWatcher(dirPath); + } + } + } + if (removeAtRoot) { + removeDirectoryWatcher(rootPath); } } - function stopWatchFailedLookupLocationOfResolutionFrom({ failedLookupLocations }: ResolutionWithFailedLookupLocations, startIndex: number) { - for (let i = startIndex; i < failedLookupLocations.length; i++) { - const failedLookupLocation = failedLookupLocations[i]; - const failedLookupLocationPath = resolutionHost.toPath(failedLookupLocation); - const refCount = customFailedLookupPaths.get(failedLookupLocationPath); - if (refCount) { - if (refCount === 1) { - customFailedLookupPaths.delete(failedLookupLocationPath); - } - else { - Debug.assert(refCount > 1); - customFailedLookupPaths.set(failedLookupLocationPath, refCount - 1); - } - } - const { dirPath, ignore } = getDirectoryToWatchFailedLookupLocation(failedLookupLocation, failedLookupLocationPath); - if (!ignore) { - const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath); - // Do not close the watcher yet since it might be needed by other failed lookup locations. - dirWatcher.refCount--; - } - } + function removeDirectoryWatcher(dirPath: string) { + const dirWatcher = directoryWatchesOfFailedLookups.get(dirPath); + // Do not close the watcher yet since it might be needed by other failed lookup locations. + dirWatcher.refCount--; } function createDirectoryWatcher(directory: string, dirPath: Path) { diff --git a/src/compiler/transformers/jsx.ts b/src/compiler/transformers/jsx.ts index 94e41af9c28..25e1ae02ef8 100644 --- a/src/compiler/transformers/jsx.ts +++ b/src/compiler/transformers/jsx.ts @@ -122,7 +122,7 @@ namespace ts { } const element = createExpressionForJsxElement( - context.getEmitResolver().getJsxFactoryEntity(), + context.getEmitResolver().getJsxFactoryEntity(currentSourceFile), compilerOptions.reactNamespace, tagName, objectProperties, @@ -140,7 +140,7 @@ namespace ts { function visitJsxOpeningFragment(node: JsxOpeningFragment, children: ReadonlyArray, isChild: boolean, location: TextRange) { const element = createExpressionForJsxFragment( - context.getEmitResolver().getJsxFactoryEntity(), + context.getEmitResolver().getJsxFactoryEntity(currentSourceFile), compilerOptions.reactNamespace, mapDefined(children, transformJsxChildToExpression), node, diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index b55dc583aa9..a4f4cb869dc 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -1728,7 +1728,7 @@ var __importStar = (this && this.__importStar) || function (mod) { if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; -}` +};` }; // emit helper for `import Name from "foo"` @@ -1738,6 +1738,6 @@ var __importStar = (this && this.__importStar) || function (mod) { text: ` var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; -}` +};` }; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 4f5dc46f4fc..3779faa1e4b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2473,7 +2473,7 @@ namespace ts { */ export interface SourceFileLike { readonly text: string; - lineMap: ReadonlyArray; + lineMap?: ReadonlyArray; } @@ -2568,6 +2568,9 @@ namespace ts { /* @internal */ ambientModuleNames: ReadonlyArray; /* @internal */ checkJsDirective: CheckJsDirective | undefined; /* @internal */ version: string; + /* @internal */ pragmas: PragmaMap; + /* @internal */ localJsxNamespace?: __String; + /* @internal */ localJsxFactory?: EntityName; } export interface Bundle extends Node { @@ -2868,7 +2871,7 @@ namespace ts { /* @internal */ getExportsAndPropertiesOfModule(moduleSymbol: Symbol): Symbol[]; getAllAttributesTypeFromJsxOpeningLikeElement(elementNode: JsxOpeningLikeElement): Type | undefined; - getJsxIntrinsicTagNames(): Symbol[]; + getJsxIntrinsicTagNamesAt(location: Node): Symbol[]; isOptionalParameter(node: ParameterDeclaration): boolean; getAmbientModules(): Symbol[]; @@ -2934,7 +2937,7 @@ namespace ts { /* @internal */ isArrayLikeType(type: Type): boolean; /* @internal */ getAllPossiblePropertiesOfTypes(type: ReadonlyArray): Symbol[]; /* @internal */ resolveName(name: string, location: Node, meaning: SymbolFlags, excludeGlobals: boolean): Symbol | undefined; - /* @internal */ getJsxNamespace(): string; + /* @internal */ getJsxNamespace(location?: Node): string; /** * Note that this will return undefined in the following case: @@ -3208,7 +3211,7 @@ namespace ts { getTypeReferenceDirectivesForSymbol(symbol: Symbol, meaning?: SymbolFlags): string[]; isLiteralConstDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): boolean; writeLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration, writer: EmitTextWriter): void; - getJsxFactoryEntity(): EntityName; + getJsxFactoryEntity(location?: Node): EntityName; } export const enum SymbolFlags { @@ -4025,8 +4028,14 @@ namespace ts { export enum DiagnosticCategory { Warning, Error, + Suggestion, Message } + /* @internal */ + export function diagnosticCategoryName(d: { category: DiagnosticCategory }, lowerCase = true): string { + const name = DiagnosticCategory[d.category]; + return lowerCase ? name.toLowerCase() : name; + } export enum ModuleResolutionKind { Classic = 1, @@ -5138,4 +5147,127 @@ namespace ts { Parameters = CommaDelimited | SpaceBetweenSiblings | SingleLine | Parenthesis, IndexSignatureParameters = CommaDelimited | SpaceBetweenSiblings | SingleLine | Indented | SquareBrackets, } + + /* @internal */ + export const enum PragmaKindFlags { + None = 0, + /** + * Triple slash comment of the form + * /// + */ + TripleSlashXML = 1 << 0, + /** + * Single line comment of the form + * // @pragma-name argval1 argval2 + * or + * /// @pragma-name argval1 argval2 + */ + SingleLine = 1 << 1, + /** + * Multiline non-jsdoc pragma of the form + * /* @pragma-name argval1 argval2 * / + */ + MultiLine = 1 << 2, + All = TripleSlashXML | SingleLine | MultiLine, + Default = All, + } + + /* @internal */ + interface PragmaArgumentSpecification { + name: TName; // Determines the name of the key in the resulting parsed type, type parameter to cause literal type inference + optional?: boolean; + captureSpan?: boolean; + } + + /* @internal */ + export interface PragmaDefinition { + args?: [PragmaArgumentSpecification] | [PragmaArgumentSpecification, PragmaArgumentSpecification] | [PragmaArgumentSpecification, PragmaArgumentSpecification, PragmaArgumentSpecification]; + // If not present, defaults to PragmaKindFlags.Default + kind?: PragmaKindFlags; + } + + /** + * This function only exists to cause exact types to be inferred for all the literals within `commentPragmas` + */ + /* @internal */ + function _contextuallyTypePragmas}, K1 extends string, K2 extends string, K3 extends string>(args: T): T { + return args; + } + + // While not strictly a type, this is here because `PragmaMap` needs to be here to be used with `SourceFile`, and we don't + // fancy effectively defining it twice, once in value-space and once in type-space + /* @internal */ + export const commentPragmas = _contextuallyTypePragmas({ + "reference": { + args: [ + { name: "types", optional: true, captureSpan: true }, + { name: "path", optional: true, captureSpan: true }, + { name: "no-default-lib", optional: true } + ], + kind: PragmaKindFlags.TripleSlashXML + }, + "amd-dependency": { + args: [{ name: "path" }, { name: "name", optional: true }], + kind: PragmaKindFlags.TripleSlashXML + }, + "amd-module": { + args: [{ name: "name" }], + kind: PragmaKindFlags.TripleSlashXML + }, + "ts-check": { + kind: PragmaKindFlags.SingleLine + }, + "ts-nocheck": { + kind: PragmaKindFlags.SingleLine + }, + "jsx": { + args: [{ name: "factory" }], + kind: PragmaKindFlags.MultiLine + }, + }); + + /* @internal */ + type PragmaArgTypeMaybeCapture = TDesc extends {captureSpan: true} ? {value: string, pos: number, end: number} : string; + + /* @internal */ + type PragmaArgTypeOptional = + TDesc extends {optional: true} + ? {[K in TName]?: PragmaArgTypeMaybeCapture} + : {[K in TName]: PragmaArgTypeMaybeCapture}; + + /** + * Maps a pragma definition into the desired shape for its arguments object + * Maybe the below is a good argument for types being iterable on struture in some way. + */ + /* @internal */ + type PragmaArgumentType = + T extends { args: [PragmaArgumentSpecification, PragmaArgumentSpecification, PragmaArgumentSpecification] } + ? PragmaArgTypeOptional & PragmaArgTypeOptional & PragmaArgTypeOptional + : T extends { args: [PragmaArgumentSpecification, PragmaArgumentSpecification] } + ? PragmaArgTypeOptional & PragmaArgTypeOptional + : T extends { args: [PragmaArgumentSpecification] } + ? PragmaArgTypeOptional + : object; + // The above fallback to `object` when there's no args to allow `{}` (as intended), but not the number 2, for example + // TODO: Swap to `undefined` for a cleaner API once strictNullChecks is enabled + + type ConcretePragmaSpecs = typeof commentPragmas; + + /* @internal */ + export type PragmaPsuedoMap = {[K in keyof ConcretePragmaSpecs]?: {arguments: PragmaArgumentType, range: CommentRange}}; + + /* @internal */ + export type PragmaPsuedoMapEntry = {[K in keyof PragmaPsuedoMap]: {name: K, args: PragmaPsuedoMap[K]}}[keyof PragmaPsuedoMap]; + + /** + * A strongly-typed es6 map of pragma entries, the values of which are either a single argument + * value (if only one was found), or an array of multiple argument values if the pragma is present + * in multiple places + */ + /* @internal */ + export interface PragmaMap extends Map { + set(key: TKey, value: PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][]): this; + get(key: TKey): PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][]; + forEach(action: (value: PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][], key: TKey) => void): void; + } } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index af0dc443e92..63c8d6989f4 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1989,40 +1989,6 @@ namespace ts { return undefined; } - export function getFileReferenceFromReferencePath(comment: string, commentRange: CommentRange): ReferencePathMatchResult { - const simpleReferenceRegEx = /^\/\/\/\s* { if (!ts.isAnySupportedFileExtension(fileName)) return; - const errors = this.getDiagnostics(fileName); + const errors = this.getDiagnostics(fileName).filter(e => e.category !== ts.DiagnosticCategory.Suggestion); if (errors.length) { this.printErrorLog(/*expectErrors*/ false, errors); const error = errors[0]; @@ -1236,20 +1239,22 @@ Actual: ${stringify(fullActual)}`); return this.languageService.findReferences(this.activeFile.fileName, this.currentCaretPosition); } - public getSyntacticDiagnostics(expected: string) { + public getSyntacticDiagnostics(expected: ReadonlyArray) { const diagnostics = this.languageService.getSyntacticDiagnostics(this.activeFile.fileName); this.testDiagnostics(expected, diagnostics); } - public getSemanticDiagnostics(expected: string) { + public getSemanticDiagnostics(expected: ReadonlyArray) { const diagnostics = this.languageService.getSemanticDiagnostics(this.activeFile.fileName); this.testDiagnostics(expected, diagnostics); } - private testDiagnostics(expected: string, diagnostics: ReadonlyArray) { - const realized = ts.realizeDiagnostics(diagnostics, "\r\n"); - const actual = stringify(realized); - assert.equal(actual, expected); + public getSuggestionDiagnostics(expected: ReadonlyArray): void { + this.testDiagnostics(expected, this.languageService.getSuggestionDiagnostics(this.activeFile.fileName)); + } + + private testDiagnostics(expected: ReadonlyArray, diagnostics: ReadonlyArray) { + assert.deepEqual(ts.realizeDiagnostics(diagnostics, ts.newLineCharacter), expected); } public verifyQuickInfoAt(markerName: string, expectedText: string, expectedDocumentation?: string) { @@ -4321,14 +4326,18 @@ namespace FourSlashInterface { this.state.verifyQuickInfoDisplayParts(kind, kindModifiers, textSpan, displayParts, documentation, tags); } - public getSyntacticDiagnostics(expected: string) { + public getSyntacticDiagnostics(expected: ReadonlyArray) { this.state.getSyntacticDiagnostics(expected); } - public getSemanticDiagnostics(expected: string) { + public getSemanticDiagnostics(expected: ReadonlyArray) { this.state.getSemanticDiagnostics(expected); } + public getSuggestionDiagnostics(expected: ReadonlyArray) { + this.state.getSuggestionDiagnostics(expected); + } + public ProjectInfo(expected: string[]) { this.state.verifyProjectInfo(expected); } diff --git a/src/harness/harness.ts b/src/harness/harness.ts index d3bd537ad4c..e2bed4f0318 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -242,7 +242,7 @@ namespace Utils { start: diagnostic.start, length: diagnostic.length, messageText: ts.flattenDiagnosticMessageText(diagnostic.messageText, Harness.IO.newLine()), - category: (ts).DiagnosticCategory[diagnostic.category], + category: ts.diagnosticCategoryName(diagnostic, /*lowerCase*/ false), code: diagnostic.code }; } @@ -1376,7 +1376,7 @@ namespace Harness { .split("\n") .map(s => s.length > 0 && s.charAt(s.length - 1) === "\r" ? s.substr(0, s.length - 1) : s) .filter(s => s.length > 0) - .map(s => "!!! " + ts.DiagnosticCategory[error.category].toLowerCase() + " TS" + error.code + ": " + s); + .map(s => "!!! " + ts.diagnosticCategoryName(error) + " TS" + error.code + ": " + s); errLines.forEach(e => outputLines += (newLine() + e)); errorsReported++; diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index c38ab1f3c6d..503246c72ca 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -402,6 +402,9 @@ namespace Harness.LanguageService { getSemanticDiagnostics(fileName: string): ts.Diagnostic[] { return unwrapJSONCallResult(this.shim.getSemanticDiagnostics(fileName)); } + getSuggestionDiagnostics(fileName: string): ts.Diagnostic[] { + return unwrapJSONCallResult(this.shim.getSuggestionDiagnostics(fileName)); + } getCompilerOptionsDiagnostics(): ts.Diagnostic[] { return unwrapJSONCallResult(this.shim.getCompilerOptionsDiagnostics()); } diff --git a/src/harness/typeWriter.ts b/src/harness/typeWriter.ts index bc25bfd12d6..060dacebdca 100644 --- a/src/harness/typeWriter.ts +++ b/src/harness/typeWriter.ts @@ -79,7 +79,7 @@ class TypeWriterWalker { // Workaround to ensure we output 'C' instead of 'typeof C' for base class expressions // let type = this.checker.getTypeAtLocation(node); const type = node.parent && ts.isExpressionWithTypeArgumentsInClassExtendsClause(node.parent) && this.checker.getTypeAtLocation(node.parent) || this.checker.getTypeAtLocation(node); - const typeString = type ? this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation) : "No type information available!"; + const typeString = type ? this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.AllowUniqueESSymbolType) : "No type information available!"; return { line: lineAndCharacter.line, syntaxKind: node.kind, diff --git a/src/harness/unittests/session.ts b/src/harness/unittests/session.ts index 765fc29ee49..b690045d7c1 100644 --- a/src/harness/unittests/session.ts +++ b/src/harness/unittests/session.ts @@ -216,6 +216,7 @@ namespace ts.server { CommandNames.GeterrForProject, CommandNames.SemanticDiagnosticsSync, CommandNames.SyntacticDiagnosticsSync, + CommandNames.SuggestionDiagnosticsSync, CommandNames.NavBar, CommandNames.NavBarFull, CommandNames.Navto, diff --git a/src/harness/unittests/textChanges.ts b/src/harness/unittests/textChanges.ts index e3f67b8c513..df940fa8b74 100644 --- a/src/harness/unittests/textChanges.ts +++ b/src/harness/unittests/textChanges.ts @@ -28,17 +28,14 @@ namespace ts { } // validate that positions that were recovered from the printed text actually match positions that will be created if the same text is parsed. - function verifyPositions({ text, node }: textChanges.NonFormattedText): void { + function verifyPositions(node: Node, text: string): void { const nodeList = flattenNodes(node); const sourceFile = createSourceFile("f.ts", text, ScriptTarget.ES2015); const parsedNodeList = flattenNodes(sourceFile.statements[0]); - Debug.assert(nodeList.length === parsedNodeList.length); - for (let i = 0; i < nodeList.length; i++) { - const left = nodeList[i]; - const right = parsedNodeList[i]; + zipWith(nodeList, parsedNodeList, (left, right) => { Debug.assert(left.pos === right.pos); Debug.assert(left.end === right.end); - } + }); function flattenNodes(n: Node) { const data: (Node | NodeArray)[] = []; @@ -57,9 +54,9 @@ namespace ts { Harness.Baseline.runBaseline(`textChanges/${caption}.js`, () => { const sourceFile = createSourceFile("source.ts", text, ScriptTarget.ES2015, /*setParentNodes*/ true); const rulesProvider = getRuleProvider(placeOpenBraceOnNewLineForFunctions); - const changeTracker = new textChanges.ChangeTracker(newLineCharacter, rulesProvider, validateNodes ? verifyPositions : undefined); + const changeTracker = new textChanges.ChangeTracker(newLineCharacter, rulesProvider); testBlock(sourceFile, changeTracker); - const changes = changeTracker.getChanges(); + const changes = changeTracker.getChanges(validateNodes ? verifyPositions : undefined); assert.equal(changes.length, 1); assert.equal(changes[0].fileName, sourceFile.fileName); const modified = textChanges.applyChanges(sourceFile.text, changes[0].textChanges); diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index e09dff2a6d5..f596896aacb 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -145,6 +145,12 @@ namespace ts.projectSystem { return map; } + function createHostModuleResolutionTrace(host: TestServerHost & ModuleResolutionHost) { + const resolutionTrace: string[] = []; + host.trace = resolutionTrace.push.bind(resolutionTrace); + return resolutionTrace; + } + export function toExternalFile(fileName: string): protocol.ExternalFile { return { fileName }; } @@ -467,12 +473,12 @@ namespace ts.projectSystem { verifyDiagnostics(actual, []); } - function checkErrorMessage(session: TestSession, eventName: "syntaxDiag" | "semanticDiag", diagnostics: protocol.DiagnosticEventBody) { - checkNthEvent(session, ts.server.toEvent(eventName, diagnostics), 0, /*isMostRecent*/ false); + function checkErrorMessage(session: TestSession, eventName: protocol.DiagnosticEventKind, diagnostics: protocol.DiagnosticEventBody, isMostRecent = false): void { + checkNthEvent(session, ts.server.toEvent(eventName, diagnostics), 0, isMostRecent); } - function checkCompleteEvent(session: TestSession, numberOfCurrentEvents: number, expectedSequenceId: number) { - checkNthEvent(session, ts.server.toEvent("requestCompleted", { request_seq: expectedSequenceId }), numberOfCurrentEvents - 1, /*isMostRecent*/ true); + function checkCompleteEvent(session: TestSession, numberOfCurrentEvents: number, expectedSequenceId: number, isMostRecent = true): void { + checkNthEvent(session, ts.server.toEvent("requestCompleted", { request_seq: expectedSequenceId }), numberOfCurrentEvents - 1, isMostRecent); } function checkProjectUpdatedInBackgroundEvent(session: TestSession, openFiles: string[]) { @@ -3076,8 +3082,13 @@ namespace ts.projectSystem { host.runQueuedImmediateCallbacks(); assert.isFalse(hasError()); checkErrorMessage(session, "semanticDiag", { file: untitledFile, diagnostics: [] }); + session.clearMessages(); + host.runQueuedImmediateCallbacks(1); + assert.isFalse(hasError()); + checkErrorMessage(session, "suggestionDiag", { file: untitledFile, diagnostics: [] }); checkCompleteEvent(session, 2, expectedSequenceId); + session.clearMessages(); } it("has projectRoot", () => { @@ -3136,6 +3147,10 @@ namespace ts.projectSystem { host.runQueuedImmediateCallbacks(); checkErrorMessage(session, "semanticDiag", { file: app.path, diagnostics: [] }); + session.clearMessages(); + + host.runQueuedImmediateCallbacks(1); + checkErrorMessage(session, "suggestionDiag", { file: app.path, diagnostics: [] }); checkCompleteEvent(session, 2, expectedSequenceId); session.clearMessages(); } @@ -3201,8 +3216,7 @@ namespace ts.projectSystem { content: "export let x = 1" }; const host: TestServerHost & ModuleResolutionHost = createServerHost([file1, lib]); - const resolutionTrace: string[] = []; - host.trace = resolutionTrace.push.bind(resolutionTrace); + const resolutionTrace = createHostModuleResolutionTrace(host); const projectService = createProjectService(host, { typingsInstaller: new TestTypingsInstaller("/a/cache", /*throttleLimit*/5, host) }); projectService.setCompilerOptionsForInferredProjects({ traceResolution: true, allowJs: true }); @@ -3934,18 +3948,17 @@ namespace ts.projectSystem { session.clearMessages(); host.runQueuedImmediateCallbacks(); - const moduleNotFound = Diagnostics.Cannot_find_module_0; const startOffset = file1.content.indexOf('"') + 1; checkErrorMessage(session, "semanticDiag", { - file: file1.path, diagnostics: [{ - start: { line: 1, offset: startOffset }, - end: { line: 1, offset: startOffset + '"pad"'.length }, - text: formatStringFromArgs(moduleNotFound.message, ["pad"]), - code: moduleNotFound.code, - category: DiagnosticCategory[moduleNotFound.category].toLowerCase(), - source: undefined - }] + file: file1.path, + diagnostics: [ + createDiagnostic({ line: 1, offset: startOffset }, { line: 1, offset: startOffset + '"pad"'.length }, Diagnostics.Cannot_find_module_0, ["pad"]) + ], }); + session.clearMessages(); + + host.runQueuedImmediateCallbacks(1); + checkErrorMessage(session, "suggestionDiag", { file: file1.path, diagnostics: [] }); checkCompleteEvent(session, 2, expectedSequenceId); session.clearMessages(); @@ -3966,6 +3979,63 @@ namespace ts.projectSystem { host.runQueuedImmediateCallbacks(); checkErrorMessage(session, "semanticDiag", { file: file1.path, diagnostics: [] }); }); + + it("info diagnostics", () => { + const file: FileOrFolder = { + path: "/a.js", + content: 'require("b")', + }; + + const host = createServerHost([file]); + const session = createSession(host, { canUseEvents: true }); + const service = session.getProjectService(); + + session.executeCommandSeq({ + command: server.CommandNames.Open, + arguments: { file: file.path, fileContent: file.content }, + }); + + checkNumberOfProjects(service, { inferredProjects: 1 }); + session.clearMessages(); + const expectedSequenceId = session.getNextSeq(); + host.checkTimeoutQueueLengthAndRun(2); + + checkProjectUpdatedInBackgroundEvent(session, [file.path]); + session.clearMessages(); + + session.executeCommandSeq({ + command: server.CommandNames.Geterr, + arguments: { + delay: 0, + files: [file.path], + } + }); + + host.checkTimeoutQueueLengthAndRun(1); + + checkErrorMessage(session, "syntaxDiag", { file: file.path, diagnostics: [] }, /*isMostRecent*/ true); + session.clearMessages(); + + host.runQueuedImmediateCallbacks(1); + + checkErrorMessage(session, "semanticDiag", { file: file.path, diagnostics: [] }); + session.clearMessages(); + + host.runQueuedImmediateCallbacks(1); + + checkErrorMessage(session, "suggestionDiag", { + file: file.path, + diagnostics: [ + createDiagnostic({ line: 1, offset: 1 }, { line: 1, offset: 13 }, Diagnostics.File_is_a_CommonJS_module_it_may_be_converted_to_an_ES6_module) + ], + }); + checkCompleteEvent(session, 2, expectedSequenceId); + session.clearMessages(); + }); + + function createDiagnostic(start: protocol.Location, end: protocol.Location, message: DiagnosticMessage, args: ReadonlyArray = []): protocol.Diagnostic { + return { start, end, text: formatStringFromArgs(message.message, args), code: message.code, category: diagnosticCategoryName(message), source: undefined }; + } }); describe("tsserverProjectSystem Configure file diagnostics events", () => { @@ -5154,9 +5224,15 @@ namespace ts.projectSystem { // the semanticDiag message host.runQueuedImmediateCallbacks(); - assert.equal(host.getOutput().length, 2, "expect 2 messages"); + assert.equal(host.getOutput().length, 1); const e2 = getMessage(0); assert.equal(e2.event, "semanticDiag"); + session.clearMessages(); + + host.runQueuedImmediateCallbacks(1); + assert.equal(host.getOutput().length, 2); + const e3 = getMessage(0); + assert.equal(e3.event, "suggestionDiag"); verifyRequestCompleted(getErrId, 1); cancellationToken.resetToken(); @@ -5194,6 +5270,7 @@ namespace ts.projectSystem { return JSON.parse(server.extractMessage(host.getOutput()[n])); } }); + it("Lower priority tasks are cancellable", () => { const f1 = { path: "/a/app.ts", @@ -5495,7 +5572,7 @@ namespace ts.projectSystem { } type CalledMaps = CalledMapsWithSingleArg | CalledMapsWithFiveArgs; function createCallsTrackingHost(host: TestServerHost) { - const calledMaps: Record> & Record, ReadonlyArray, ReadonlyArray, number]>> = { + const calledMaps: Record> & Record, ReadonlyArray, ReadonlyArray, number]>> = { fileExists: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.fileExists), directoryExists: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.directoryExists), getDirectories: setCallsTrackingWithSingleArgFn(CalledMapsWithSingleArg.getDirectories), @@ -6971,4 +7048,353 @@ namespace ts.projectSystem { assert.deepEqual(diagnostics, []); }); }); + + describe("tsserverProjectSystem module resolution caching", () => { + const projectLocation = "/user/username/projects/myproject"; + const configFile: FileOrFolder = { + path: `${projectLocation}/tsconfig.json`, + content: JSON.stringify({ compilerOptions: { traceResolution: true } }) + }; + + function getModules(module1Path: string, module2Path: string) { + const module1: FileOrFolder = { + path: module1Path, + content: `export function module1() {}` + }; + const module2: FileOrFolder = { + path: module2Path, + content: `export function module2() {}` + }; + return { module1, module2 }; + } + + function verifyTrace(resolutionTrace: string[], expected: string[]) { + assert.deepEqual(resolutionTrace, expected); + resolutionTrace.length = 0; + } + + function getExpectedFileDoesNotExistResolutionTrace(host: TestServerHost, expectedTrace: string[], foundModule: boolean, module: FileOrFolder, directory: string, file: string, ignoreIfParentMissing?: boolean) { + if (!foundModule) { + const path = combinePaths(directory, file); + if (!ignoreIfParentMissing || host.directoryExists(getDirectoryPath(path))) { + if (module.path === path) { + foundModule = true; + } + else { + expectedTrace.push(`File '${path}' does not exist.`); + } + } + } + return foundModule; + } + + function getExpectedMissedLocationResolutionTrace(host: TestServerHost, expectedTrace: string[], dirPath: string, module: FileOrFolder, moduleName: string, useNodeModules: boolean, cacheLocation?: string) { + let foundModule = false; + forEachAncestorDirectory(dirPath, dirPath => { + if (dirPath === cacheLocation) { + return foundModule; + } + + const directory = useNodeModules ? combinePaths(dirPath, nodeModules) : dirPath; + if (useNodeModules && !foundModule && !host.directoryExists(directory)) { + expectedTrace.push(`Directory '${directory}' does not exist, skipping all lookups in it.`); + return undefined; + } + foundModule = getExpectedFileDoesNotExistResolutionTrace(host, expectedTrace, foundModule, module, directory, `${moduleName}/package.json`, /*ignoreIfParentMissing*/ true); + foundModule = getExpectedFileDoesNotExistResolutionTrace(host, expectedTrace, foundModule, module, directory, `${moduleName}.ts`); + foundModule = getExpectedFileDoesNotExistResolutionTrace(host, expectedTrace, foundModule, module, directory, `${moduleName}.tsx`); + foundModule = getExpectedFileDoesNotExistResolutionTrace(host, expectedTrace, foundModule, module, directory, `${moduleName}.d.ts`); + foundModule = getExpectedFileDoesNotExistResolutionTrace(host, expectedTrace, foundModule, module, directory, `${moduleName}/index.ts`, /*ignoreIfParentMissing*/ true); + if (useNodeModules && !foundModule) { + expectedTrace.push(`Directory '${directory}/@types' does not exist, skipping all lookups in it.`); + } + return foundModule ? true : undefined; + }); + } + + function getExpectedResolutionTraceHeader(expectedTrace: string[], file: FileOrFolder, moduleName: string) { + expectedTrace.push( + `======== Resolving module '${moduleName}' from '${file.path}'. ========`, + `Module resolution kind is not specified, using 'NodeJs'.` + ); + } + + function getExpectedResolutionTraceFooter(expectedTrace: string[], module: FileOrFolder, moduleName: string, addRealPathTrace: boolean, ignoreModuleFileFound?: boolean) { + if (!ignoreModuleFileFound) { + expectedTrace.push(`File '${module.path}' exist - use it as a name resolution result.`); + } + if (addRealPathTrace) { + expectedTrace.push(`Resolving real path for '${module.path}', result '${module.path}'.`); + } + expectedTrace.push(`======== Module name '${moduleName}' was successfully resolved to '${module.path}'. ========`); + } + + function getExpectedRelativeModuleResolutionTrace(host: TestServerHost, file: FileOrFolder, module: FileOrFolder, moduleName: string, expectedTrace: string[] = []) { + getExpectedResolutionTraceHeader(expectedTrace, file, moduleName); + expectedTrace.push(`Loading module as file / folder, candidate module location '${removeFileExtension(module.path)}', target file type 'TypeScript'.`); + getExpectedMissedLocationResolutionTrace(host, expectedTrace, getDirectoryPath(normalizePath(combinePaths(getDirectoryPath(file.path), moduleName))), module, moduleName.substring(moduleName.lastIndexOf("/") + 1), /*useNodeModules*/ false); + getExpectedResolutionTraceFooter(expectedTrace, module, moduleName, /*addRealPathTrace*/ false); + return expectedTrace; + } + + function getExpectedNonRelativeModuleResolutionTrace(host: TestServerHost, file: FileOrFolder, module: FileOrFolder, moduleName: string, expectedTrace: string[] = []) { + getExpectedResolutionTraceHeader(expectedTrace, file, moduleName); + expectedTrace.push(`Loading module '${moduleName}' from 'node_modules' folder, target file type 'TypeScript'.`); + getExpectedMissedLocationResolutionTrace(host, expectedTrace, getDirectoryPath(file.path), module, moduleName, /*useNodeModules*/ true); + getExpectedResolutionTraceFooter(expectedTrace, module, moduleName, /*addRealPathTrace*/ true); + return expectedTrace; + } + + function getExpectedNonRelativeModuleResolutionFromCacheTrace(host: TestServerHost, file: FileOrFolder, module: FileOrFolder, moduleName: string, cacheLocation: string, expectedTrace: string[] = []) { + getExpectedResolutionTraceHeader(expectedTrace, file, moduleName); + expectedTrace.push(`Loading module '${moduleName}' from 'node_modules' folder, target file type 'TypeScript'.`); + getExpectedMissedLocationResolutionTrace(host, expectedTrace, getDirectoryPath(file.path), module, moduleName, /*useNodeModules*/ true, cacheLocation); + expectedTrace.push(`Resolution for module '${moduleName}' was found in cache from location '${cacheLocation}'.`); + getExpectedResolutionTraceFooter(expectedTrace, module, moduleName, /*addRealPathTrace*/ true, /*ignoreModuleFileFound*/ true); + return expectedTrace; + } + + function getExpectedReusingResolutionFromOldProgram(file: FileOrFolder, moduleName: string) { + return `Reusing resolution of module '${moduleName}' to file '${file.path}' from old program.`; + } + + function verifyWatchesWithConfigFile(host: TestServerHost, files: FileOrFolder[], openFile: FileOrFolder) { + checkWatchedFiles(host, mapDefined(files, f => f === openFile ? undefined : f.path)); + checkWatchedDirectories(host, [], /*recursive*/ false); + const configDirectory = getDirectoryPath(configFile.path); + checkWatchedDirectories(host, [configDirectory, `${configDirectory}/${nodeModulesAtTypes}`], /*recursive*/ true); + } + + describe("from files in same folder", () => { + function getFiles(fileContent: string) { + const file1: FileOrFolder = { + path: `${projectLocation}/src/file1.ts`, + content: fileContent + }; + const file2: FileOrFolder = { + path: `${projectLocation}/src/file2.ts`, + content: fileContent + }; + return { file1, file2 }; + } + + it("relative module name", () => { + const module1Name = "./module1"; + const module2Name = "../module2"; + const fileContent = `import { module1 } from "${module1Name}";import { module2 } from "${module2Name}";`; + const { file1, file2 } = getFiles(fileContent); + const { module1, module2 } = getModules(`${projectLocation}/src/module1.ts`, `${projectLocation}/module2.ts`); + const files = [module1, module2, file1, file2, configFile, libFile]; + const host = createServerHost(files); + const resolutionTrace = createHostModuleResolutionTrace(host); + const service = createProjectService(host); + service.openClientFile(file1.path); + const expectedTrace = getExpectedRelativeModuleResolutionTrace(host, file1, module1, module1Name); + getExpectedRelativeModuleResolutionTrace(host, file1, module2, module2Name, expectedTrace); + verifyTrace(resolutionTrace, expectedTrace); + verifyWatchesWithConfigFile(host, files, file1); + + file1.content += fileContent; + file2.content += fileContent; + host.reloadFS(files); + host.runQueuedTimeoutCallbacks(); + verifyTrace(resolutionTrace, [ + getExpectedReusingResolutionFromOldProgram(file1, module1Name), + getExpectedReusingResolutionFromOldProgram(file1, module2Name) + ]); + verifyWatchesWithConfigFile(host, files, file1); + }); + + it("non relative module name", () => { + const module1Name = "module1"; + const module2Name = "module2"; + const fileContent = `import { module1 } from "${module1Name}";import { module2 } from "${module2Name}";`; + const { file1, file2 } = getFiles(fileContent); + const { module1, module2 } = getModules(`${projectLocation}/src/node_modules/module1/index.ts`, `${projectLocation}/node_modules/module2/index.ts`); + const files = [module1, module2, file1, file2, configFile, libFile]; + const host = createServerHost(files); + const resolutionTrace = createHostModuleResolutionTrace(host); + const service = createProjectService(host); + service.openClientFile(file1.path); + const expectedTrace = getExpectedNonRelativeModuleResolutionTrace(host, file1, module1, module1Name); + getExpectedNonRelativeModuleResolutionTrace(host, file1, module2, module2Name, expectedTrace); + verifyTrace(resolutionTrace, expectedTrace); + verifyWatchesWithConfigFile(host, files, file1); + + file1.content += fileContent; + file2.content += fileContent; + host.reloadFS(files); + host.runQueuedTimeoutCallbacks(); + verifyTrace(resolutionTrace, [ + getExpectedReusingResolutionFromOldProgram(file1, module1Name), + getExpectedReusingResolutionFromOldProgram(file1, module2Name) + ]); + verifyWatchesWithConfigFile(host, files, file1); + }); + }); + + describe("from files in different folders", () => { + function getFiles(fileContent1: string, fileContent2 = fileContent1, fileContent3 = fileContent1, fileContent4 = fileContent1) { + const file1: FileOrFolder = { + path: `${projectLocation}/product/src/file1.ts`, + content: fileContent1 + }; + const file2: FileOrFolder = { + path: `${projectLocation}/product/src/feature/file2.ts`, + content: fileContent2 + }; + const file3: FileOrFolder = { + path: `${projectLocation}/product/test/src/file3.ts`, + content: fileContent3 + }; + const file4: FileOrFolder = { + path: `${projectLocation}/product/test/file4.ts`, + content: fileContent4 + }; + return { file1, file2, file3, file4 }; + } + + it("relative module name", () => { + const module1Name = "./module1"; + const module2Name = "../module2"; + const module3Name = "../module1"; + const module4Name = "../../module2"; + const module5Name = "../../src/module1"; + const module6Name = "../src/module1"; + const fileContent1 = `import { module1 } from "${module1Name}";import { module2 } from "${module2Name}";`; + const fileContent2 = `import { module1 } from "${module3Name}";import { module2 } from "${module4Name}";`; + const fileContent3 = `import { module1 } from "${module5Name}";import { module2 } from "${module4Name}";`; + const fileContent4 = `import { module1 } from "${module6Name}";import { module2 } from "${module2Name}";`; + const { file1, file2, file3, file4 } = getFiles(fileContent1, fileContent2, fileContent3, fileContent4); + const { module1, module2 } = getModules(`${projectLocation}/product/src/module1.ts`, `${projectLocation}/product/module2.ts`); + const files = [module1, module2, file1, file2, file3, file4, configFile, libFile]; + const host = createServerHost(files); + const resolutionTrace = createHostModuleResolutionTrace(host); + const service = createProjectService(host); + service.openClientFile(file1.path); + const expectedTrace = getExpectedRelativeModuleResolutionTrace(host, file1, module1, module1Name); + getExpectedRelativeModuleResolutionTrace(host, file1, module2, module2Name, expectedTrace); + getExpectedRelativeModuleResolutionTrace(host, file2, module1, module3Name, expectedTrace); + getExpectedRelativeModuleResolutionTrace(host, file2, module2, module4Name, expectedTrace); + getExpectedRelativeModuleResolutionTrace(host, file4, module1, module6Name, expectedTrace); + getExpectedRelativeModuleResolutionTrace(host, file4, module2, module2Name, expectedTrace); + getExpectedRelativeModuleResolutionTrace(host, file3, module1, module5Name, expectedTrace); + getExpectedRelativeModuleResolutionTrace(host, file3, module2, module4Name, expectedTrace); + verifyTrace(resolutionTrace, expectedTrace); + verifyWatchesWithConfigFile(host, files, file1); + + file1.content += fileContent1; + file2.content += fileContent2; + file3.content += fileContent3; + file4.content += fileContent4; + host.reloadFS(files); + host.runQueuedTimeoutCallbacks(); + + verifyTrace(resolutionTrace, [ + getExpectedReusingResolutionFromOldProgram(file1, module1Name), + getExpectedReusingResolutionFromOldProgram(file1, module2Name) + ]); + verifyWatchesWithConfigFile(host, files, file1); + }); + + it("non relative module name", () => { + const module1Name = "module1"; + const module2Name = "module2"; + const fileContent = `import { module1 } from "${module1Name}";import { module2 } from "${module2Name}";`; + const { file1, file2, file3, file4 } = getFiles(fileContent); + const { module1, module2 } = getModules(`${projectLocation}/product/node_modules/module1/index.ts`, `${projectLocation}/node_modules/module2/index.ts`); + const files = [module1, module2, file1, file2, file3, file4, configFile, libFile]; + const host = createServerHost(files); + const resolutionTrace = createHostModuleResolutionTrace(host); + const service = createProjectService(host); + service.openClientFile(file1.path); + const expectedTrace = getExpectedNonRelativeModuleResolutionTrace(host, file1, module1, module1Name); + getExpectedNonRelativeModuleResolutionTrace(host, file1, module2, module2Name, expectedTrace); + getExpectedNonRelativeModuleResolutionFromCacheTrace(host, file2, module1, module1Name, getDirectoryPath(file1.path), expectedTrace); + getExpectedNonRelativeModuleResolutionFromCacheTrace(host, file2, module2, module2Name, getDirectoryPath(file1.path), expectedTrace); + getExpectedNonRelativeModuleResolutionFromCacheTrace(host, file4, module1, module1Name, `${projectLocation}/product`, expectedTrace); + getExpectedNonRelativeModuleResolutionFromCacheTrace(host, file4, module2, module2Name, `${projectLocation}/product`, expectedTrace); + getExpectedNonRelativeModuleResolutionFromCacheTrace(host, file3, module1, module1Name, getDirectoryPath(file4.path), expectedTrace); + getExpectedNonRelativeModuleResolutionFromCacheTrace(host, file3, module2, module2Name, getDirectoryPath(file4.path), expectedTrace); + verifyTrace(resolutionTrace, expectedTrace); + verifyWatchesWithConfigFile(host, files, file1); + + file1.content += fileContent; + file2.content += fileContent; + file3.content += fileContent; + file4.content += fileContent; + host.reloadFS(files); + host.runQueuedTimeoutCallbacks(); + + verifyTrace(resolutionTrace, [ + getExpectedReusingResolutionFromOldProgram(file1, module1Name), + getExpectedReusingResolutionFromOldProgram(file1, module2Name) + ]); + verifyWatchesWithConfigFile(host, files, file1); + }); + + it("non relative module name from inferred project", () => { + const module1Name = "module1"; + const module2Name = "module2"; + const file2Name = "./feature/file2"; + const file3Name = "../test/src/file3"; + const file4Name = "../test/file4"; + const importModuleContent = `import { module1 } from "${module1Name}";import { module2 } from "${module2Name}";`; + const { file1, file2, file3, file4 } = getFiles(`import "${file2Name}"; import "${file4Name}"; import "${file3Name}"; ${importModuleContent}`, importModuleContent, importModuleContent, importModuleContent); + const { module1, module2 } = getModules(`${projectLocation}/product/node_modules/module1/index.ts`, `${projectLocation}/node_modules/module2/index.ts`); + const files = [module1, module2, file1, file2, file3, file4, libFile]; + const host = createServerHost(files); + const resolutionTrace = createHostModuleResolutionTrace(host); + const service = createProjectService(host); + service.setCompilerOptionsForInferredProjects({ traceResolution: true }); + service.openClientFile(file1.path); + const expectedTrace = getExpectedRelativeModuleResolutionTrace(host, file1, file2, file2Name); + getExpectedRelativeModuleResolutionTrace(host, file1, file4, file4Name, expectedTrace); + getExpectedRelativeModuleResolutionTrace(host, file1, file3, file3Name, expectedTrace); + getExpectedNonRelativeModuleResolutionTrace(host, file1, module1, module1Name, expectedTrace); + getExpectedNonRelativeModuleResolutionTrace(host, file1, module2, module2Name, expectedTrace); + getExpectedNonRelativeModuleResolutionFromCacheTrace(host, file2, module1, module1Name, getDirectoryPath(file1.path), expectedTrace); + getExpectedNonRelativeModuleResolutionFromCacheTrace(host, file2, module2, module2Name, getDirectoryPath(file1.path), expectedTrace); + getExpectedNonRelativeModuleResolutionFromCacheTrace(host, file4, module1, module1Name, `${projectLocation}/product`, expectedTrace); + getExpectedNonRelativeModuleResolutionFromCacheTrace(host, file4, module2, module2Name, `${projectLocation}/product`, expectedTrace); + getExpectedNonRelativeModuleResolutionFromCacheTrace(host, file3, module1, module1Name, getDirectoryPath(file4.path), expectedTrace); + getExpectedNonRelativeModuleResolutionFromCacheTrace(host, file3, module2, module2Name, getDirectoryPath(file4.path), expectedTrace); + verifyTrace(resolutionTrace, expectedTrace); + + const currentDirectory = getDirectoryPath(file1.path); + const watchedFiles = mapDefined(files, f => f === file1 ? undefined : f.path); + forEachAncestorDirectory(currentDirectory, d => { + watchedFiles.push(combinePaths(d, "tsconfig.json"), combinePaths(d, "jsconfig.json")); + }); + const watchedRecursiveDirectories = getTypeRootsFromLocation(currentDirectory).concat([ + currentDirectory, `${projectLocation}/product/${nodeModules}`, + `${projectLocation}/${nodeModules}`, `${projectLocation}/product/test/${nodeModules}`, + `${projectLocation}/product/test/src/${nodeModules}` + ]); + checkWatches(); + + file1.content += importModuleContent; + file2.content += importModuleContent; + file3.content += importModuleContent; + file4.content += importModuleContent; + host.reloadFS(files); + host.runQueuedTimeoutCallbacks(); + + verifyTrace(resolutionTrace, [ + getExpectedReusingResolutionFromOldProgram(file1, file2Name), + getExpectedReusingResolutionFromOldProgram(file1, file4Name), + getExpectedReusingResolutionFromOldProgram(file1, file3Name), + getExpectedReusingResolutionFromOldProgram(file1, module1Name), + getExpectedReusingResolutionFromOldProgram(file1, module2Name) + ]); + checkWatches(); + + function checkWatches() { + checkWatchedFiles(host, watchedFiles); + checkWatchedDirectories(host, [], /*recursive*/ false); + checkWatchedDirectories(host, watchedRecursiveDirectories, /*recursive*/ true); + } + }); + }); + }); } diff --git a/src/harness/virtualFileSystemWithWatch.ts b/src/harness/virtualFileSystemWithWatch.ts index 93fdc6cdbc6..54a353a59c6 100644 --- a/src/harness/virtualFileSystemWithWatch.ts +++ b/src/harness/virtualFileSystemWithWatch.ts @@ -708,7 +708,10 @@ interface Array {}` } } - runQueuedImmediateCallbacks() { + runQueuedImmediateCallbacks(checkCount?: number) { + if (checkCount !== undefined) { + assert.equal(this.immediateCallbacks.count(), checkCount); + } this.immediateCallbacks.invoke(); } diff --git a/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl index 476ae69b584..6be77191686 100644 --- a/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -903,6 +903,15 @@ + + + + + + + + + @@ -915,6 +924,15 @@ + + + + + + + + + @@ -939,6 +957,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl index 332e2933d2a..d732d0101c3 100644 --- a/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -912,6 +912,15 @@ + + + + + + + + + @@ -924,6 +933,15 @@ + + + + + + + + + @@ -948,6 +966,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl index be0db6f399c..91b2ba9c341 100644 --- a/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -912,6 +912,15 @@ + + + + + + + + + @@ -924,6 +933,15 @@ + + + + + + + + + @@ -948,6 +966,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl index 1d0a08bdfe6..35dc89a8c24 100644 --- a/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -912,6 +912,15 @@ + + + + + + + + + @@ -924,6 +933,15 @@ + + + + + + + + + @@ -948,6 +966,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl index 9c0ffaf818e..6ab6de8613c 100644 --- a/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -903,6 +903,15 @@ + + + + + + + + + @@ -915,6 +924,15 @@ + + + + + + + + + @@ -939,6 +957,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl index a1515e25bc4..94dc752de40 100644 --- a/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -903,6 +903,15 @@ + + + + + + + + + @@ -915,6 +924,15 @@ + + + + + + + + + @@ -939,6 +957,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl index 59ede10c95b..ded26e10335 100644 --- a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -903,6 +903,15 @@ + + + + + + + + + @@ -915,6 +924,15 @@ + + + + + + + + + @@ -939,6 +957,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl index 5d0a9a141b0..38b72098bd7 100644 --- a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -893,6 +893,15 @@ + + + + + + + + + @@ -905,6 +914,15 @@ + + + + + + + + + @@ -929,6 +947,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl index f65f2418896..e12a181198d 100644 --- a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -893,6 +893,15 @@ + + + + + + + + + @@ -905,6 +914,15 @@ + + + + + + + + + @@ -929,6 +947,15 @@ + + + + + + + + + diff --git a/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl index 15c5e26b54f..b8891b5a90b 100644 --- a/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl +++ b/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl @@ -902,6 +902,15 @@ + + + + + + + + + @@ -914,6 +923,15 @@ + + + + + + + + + @@ -938,6 +956,15 @@ + + + + + + + + + diff --git a/src/server/client.ts b/src/server/client.ts index cee65c0e5a4..6f04f141957 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -75,7 +75,7 @@ namespace ts.server { return { span: this.decodeSpan(codeEdit, fileName), newText: codeEdit.newText }; } - private processRequest(command: string, args?: any): T { + private processRequest(command: string, args?: T["arguments"]): T { const request: protocol.Request = { seq: this.sequence, type: "request", @@ -343,41 +343,31 @@ namespace ts.server { } getSyntacticDiagnostics(file: string): Diagnostic[] { - const args: protocol.SyntacticDiagnosticsSyncRequestArgs = { file, includeLinePosition: true }; - - const request = this.processRequest(CommandNames.SyntacticDiagnosticsSync, args); - const response = this.processResponse(request); - - return (response.body).map(entry => this.convertDiagnostic(entry, file)); + return this.getDiagnostics(file, CommandNames.SyntacticDiagnosticsSync); } - getSemanticDiagnostics(file: string): Diagnostic[] { - const args: protocol.SemanticDiagnosticsSyncRequestArgs = { file, includeLinePosition: true }; - - const request = this.processRequest(CommandNames.SemanticDiagnosticsSync, args); - const response = this.processResponse(request); - - return (response.body).map(entry => this.convertDiagnostic(entry, file)); + return this.getDiagnostics(file, CommandNames.SemanticDiagnosticsSync); + } + getSuggestionDiagnostics(file: string): Diagnostic[] { + return this.getDiagnostics(file, CommandNames.SuggestionDiagnosticsSync); } - convertDiagnostic(entry: protocol.DiagnosticWithLinePosition, _fileName: string): Diagnostic { - let category: DiagnosticCategory; - for (const id in DiagnosticCategory) { - if (isString(id) && entry.category === id.toLowerCase()) { - category = (DiagnosticCategory)[id]; - } - } + private getDiagnostics(file: string, command: CommandNames) { + const request = this.processRequest(command, { file, includeLinePosition: true }); + const response = this.processResponse(request); - Debug.assert(category !== undefined, "convertDiagnostic: category should not be undefined"); - - return { - file: undefined, - start: entry.start, - length: entry.length, - messageText: entry.message, - category, - code: entry.code - }; + return (response.body).map(entry => { + const category = firstDefined(Object.keys(DiagnosticCategory), id => + isString(id) && entry.category === id.toLowerCase() ? (DiagnosticCategory)[id] : undefined); + return { + file: undefined, + start: entry.start, + length: entry.length, + messageText: entry.message, + category: Debug.assertDefined(category, "convertDiagnostic: category should not be undefined"), + code: entry.code + }; + }); } getCompilerOptionsDiagnostics(): Diagnostic[] { diff --git a/src/server/project.ts b/src/server/project.ts index dc949b4b221..bfd039f26fb 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -210,6 +210,9 @@ namespace ts.server { /*@internal*/ public directoryStructureHost: DirectoryStructureHost; + /*@internal*/ + public readonly getCanonicalFileName: GetCanonicalFileName; + /*@internal*/ constructor( /*@internal*/readonly projectName: string, @@ -224,6 +227,7 @@ namespace ts.server { currentDirectory: string | undefined) { this.directoryStructureHost = directoryStructureHost; this.currentDirectory = this.projectService.getNormalizedAbsolutePath(currentDirectory || ""); + this.getCanonicalFileName = this.projectService.toCanonicalFileName; this.cancellationToken = new ThrottledCancellationToken(this.projectService.cancellationToken, this.projectService.throttleWaitMilliseconds); if (!this.compilerOptions) { @@ -238,7 +242,10 @@ namespace ts.server { this.setInternalCompilerOptionsForEmittingJsFiles(); const host = this.projectService.host; - if (host.trace) { + if (this.projectService.logger.loggingEnabled()) { + this.trace = s => this.writeLog(s); + } + else if (host.trace) { this.trace = s => host.trace(s); } diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 76d954ebe23..40bee65e9f0 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -42,6 +42,7 @@ namespace ts.server.protocol { GeterrForProject = "geterrForProject", SemanticDiagnosticsSync = "semanticDiagnosticsSync", SyntacticDiagnosticsSync = "syntacticDiagnosticsSync", + SuggestionDiagnosticsSync = "suggestionDiagnosticsSync", NavBar = "navbar", /* @internal */ NavBarFull = "navbar-full", @@ -2010,6 +2011,14 @@ namespace ts.server.protocol { body?: Diagnostic[] | DiagnosticWithLinePosition[]; } + export interface SuggestionDiagnosticsSyncRequest extends FileRequest { + command: CommandTypes.SuggestionDiagnosticsSync; + arguments: SuggestionDiagnosticsSyncRequestArgs; + } + + export type SuggestionDiagnosticsSyncRequestArgs = SemanticDiagnosticsSyncRequestArgs; + export type SuggestionDiagnosticsSyncResponse = SemanticDiagnosticsSyncResponse; + /** * Synchronous request for syntactic diagnostics of one file. */ @@ -2121,7 +2130,7 @@ namespace ts.server.protocol { text: string; /** - * The category of the diagnostic message, e.g. "error" vs. "warning" + * The category of the diagnostic message, e.g. "error", "warning", or "suggestion". */ category: string; @@ -2155,8 +2164,10 @@ namespace ts.server.protocol { diagnostics: Diagnostic[]; } + export type DiagnosticEventKind = "semanticDiag" | "syntaxDiag" | "suggestionDiag"; + /** - * Event message for "syntaxDiag" and "semanticDiag" event types. + * Event message for DiagnosticEventKind event types. * These events provide syntactic and semantic errors for a file. */ export interface DiagnosticEvent extends Event { diff --git a/src/server/session.ts b/src/server/session.ts index bff19d7bc23..4f0981a3880 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -79,7 +79,7 @@ namespace ts.server { end: scriptInfo.positionToLineOffset(diag.start + diag.length), text: flattenDiagnosticMessageText(diag.messageText, "\n"), code: diag.code, - category: DiagnosticCategory[diag.category].toLowerCase(), + category: diagnosticCategoryName(diag), source: diag.source }; } @@ -95,7 +95,7 @@ namespace ts.server { const end = diag.file && convertToLocation(getLineAndCharacterOfPosition(diag.file, diag.start + diag.length)); const text = flattenDiagnosticMessageText(diag.messageText, "\n"); const { code, source } = diag; - const category = DiagnosticCategory[diag.category].toLowerCase(); + const category = diagnosticCategoryName(diag); return includeFileName ? { start, end, text, code, category, source, fileName: diag.file && diag.file.fileName } : { start, end, text, code, category, source }; } @@ -466,30 +466,26 @@ namespace ts.server { } private semanticCheck(file: NormalizedPath, project: Project) { - try { - let diags: ReadonlyArray = emptyArray; - if (!isDeclarationFileInJSOnlyNonConfiguredProject(project, file)) { - diags = project.getLanguageService().getSemanticDiagnostics(file); - } - - const bakedDiags = diags.map((diag) => formatDiag(file, project, diag)); - this.event({ file, diagnostics: bakedDiags }, "semanticDiag"); - } - catch (err) { - this.logError(err, "semantic check"); - } + const diags = isDeclarationFileInJSOnlyNonConfiguredProject(project, file) + ? emptyArray + : project.getLanguageService().getSemanticDiagnostics(file); + this.sendDiagnosticsEvent(file, project, diags, "semanticDiag"); } private syntacticCheck(file: NormalizedPath, project: Project) { + this.sendDiagnosticsEvent(file, project, project.getLanguageService().getSyntacticDiagnostics(file), "syntaxDiag"); + } + + private infoCheck(file: NormalizedPath, project: Project) { + this.sendDiagnosticsEvent(file, project, project.getLanguageService().getSuggestionDiagnostics(file), "suggestionDiag"); + } + + private sendDiagnosticsEvent(file: NormalizedPath, project: Project, diagnostics: ReadonlyArray, kind: protocol.DiagnosticEventKind): void { try { - const diags = project.getLanguageService().getSyntacticDiagnostics(file); - if (diags) { - const bakedDiags = diags.map((diag) => formatDiag(file, project, diag)); - this.event({ file, diagnostics: bakedDiags }, "syntaxDiag"); - } + this.event({ file, diagnostics: diagnostics.map(diag => formatDiag(file, project, diag)) }, kind); } catch (err) { - this.logError(err, "syntactic check"); + this.logError(err, kind); } } @@ -499,21 +495,34 @@ namespace ts.server { let index = 0; const checkOne = () => { - if (this.changeSeq === seq) { - const checkSpec = checkList[index]; - index++; - if (checkSpec.project.containsFile(checkSpec.fileName, requireOpen)) { - this.syntacticCheck(checkSpec.fileName, checkSpec.project); - if (this.changeSeq === seq) { - next.immediate(() => { - this.semanticCheck(checkSpec.fileName, checkSpec.project); - if (checkList.length > index) { - next.delay(followMs, checkOne); - } - }); - } - } + if (this.changeSeq !== seq) { + return; } + + const { fileName, project } = checkList[index]; + index++; + if (!project.containsFile(fileName, requireOpen)) { + return; + } + + this.syntacticCheck(fileName, project); + if (this.changeSeq !== seq) { + return; + } + + next.immediate(() => { + this.semanticCheck(fileName, project); + if (this.changeSeq !== seq) { + return; + } + + next.immediate(() => { + this.infoCheck(fileName, project); + if (checkList.length > index) { + next.delay(followMs, checkOne); + } + }); + }); }; if (checkList.length > index && this.changeSeq === seq) { @@ -580,7 +589,7 @@ namespace ts.server { message: flattenDiagnosticMessageText(d.messageText, this.host.newLine), start: d.start, length: d.length, - category: DiagnosticCategory[d.category].toLowerCase(), + category: diagnosticCategoryName(d), code: d.code, startLocation: d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start)), endLocation: d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start + d.length)) @@ -606,7 +615,7 @@ namespace ts.server { message: flattenDiagnosticMessageText(d.messageText, this.host.newLine), start: d.start, length: d.length, - category: DiagnosticCategory[d.category].toLowerCase(), + category: diagnosticCategoryName(d), code: d.code, source: d.source, startLocation: scriptInfo && scriptInfo.positionToLineOffset(d.start), @@ -756,6 +765,16 @@ namespace ts.server { return this.getDiagnosticsWorker(args, /*isSemantic*/ true, (project, file) => project.getLanguageService().getSemanticDiagnostics(file), args.includeLinePosition); } + private getSuggestionDiagnosticsSync(args: protocol.SuggestionDiagnosticsSyncRequestArgs): ReadonlyArray | ReadonlyArray { + const { configFile } = this.getConfigFileAndProject(args); + if (configFile) { + // Currently there are no info diagnostics for config files. + return emptyArray; + } + // isSemantic because we don't want to info diagnostics in declaration files for JS-only users + return this.getDiagnosticsWorker(args, /*isSemantic*/ true, (project, file) => project.getLanguageService().getSuggestionDiagnostics(file), args.includeLinePosition); + } + private getDocumentHighlights(args: protocol.DocumentHighlightsRequestArgs, simplifiedResult: boolean): ReadonlyArray | ReadonlyArray { const { file, project } = this.getFileAndProject(args); const position = this.getPositionInFile(args, file); @@ -1953,6 +1972,9 @@ namespace ts.server { [CommandNames.SyntacticDiagnosticsSync]: (request: protocol.SyntacticDiagnosticsSyncRequest) => { return this.requiredResponse(this.getSyntacticDiagnosticsSync(request.arguments)); }, + [CommandNames.SuggestionDiagnosticsSync]: (request: protocol.SuggestionDiagnosticsSyncRequest) => { + return this.requiredResponse(this.getSuggestionDiagnosticsSync(request.arguments)); + }, [CommandNames.Geterr]: (request: protocol.GeterrRequest) => { this.errorCheck.startNew(next => this.getDiagnostics(next, request.arguments.delay, request.arguments.files)); return this.notRequired(); diff --git a/src/services/refactors/convertToEs6Module.ts b/src/services/codefixes/convertToEs6Module.ts similarity index 85% rename from src/services/refactors/convertToEs6Module.ts rename to src/services/codefixes/convertToEs6Module.ts index 6ed9cbec2ee..d494e5c907f 100644 --- a/src/services/refactors/convertToEs6Module.ts +++ b/src/services/codefixes/convertToEs6Module.ts @@ -1,85 +1,22 @@ /* @internal */ -namespace ts.refactor { - const actionName = "Convert to ES6 module"; - const description = getLocaleSpecificMessage(Diagnostics.Convert_to_ES6_module); - registerRefactor(actionName, { getEditsForAction, getAvailableActions }); - - function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined { - const { file, startPosition } = context; - if (!isSourceFileJavaScript(file) || !file.commonJsModuleIndicator) { - return undefined; - } - - const node = getTokenAtPosition(file, startPosition, /*includeJsDocComment*/ false); - return !isAtTriggerLocation(file, node) ? undefined : [ - { - name: actionName, - description, - actions: [ - { - description, - name: actionName, - }, - ], - }, - ]; - } - - function isAtTriggerLocation(sourceFile: SourceFile, node: Node, onSecondTry = false): boolean { - switch (node.kind) { - case SyntaxKind.CallExpression: - return isAtTopLevelRequire(node as CallExpression); - case SyntaxKind.PropertyAccessExpression: - return isExportsOrModuleExportsOrAlias(sourceFile, node as PropertyAccessExpression) - || isExportsOrModuleExportsOrAlias(sourceFile, (node as PropertyAccessExpression).expression); - case SyntaxKind.VariableDeclarationList: - return isVariableDeclarationTriggerLocation(firstOrUndefined((node as VariableDeclarationList).declarations)); - case SyntaxKind.VariableDeclaration: - return isVariableDeclarationTriggerLocation(node as VariableDeclaration); - default: - return isExpression(node) && isExportsOrModuleExportsOrAlias(sourceFile, node) - || !onSecondTry && isAtTriggerLocation(sourceFile, node.parent, /*onSecondTry*/ true); - } - - function isVariableDeclarationTriggerLocation(decl: VariableDeclaration | undefined) { - return !!decl && !!decl.initializer && isExportsOrModuleExportsOrAlias(sourceFile, decl.initializer); - } - } - - function isAtTopLevelRequire(call: CallExpression): boolean { - if (!isRequireCall(call, /*checkArgumentIsStringLiteral*/ true)) { - return false; - } - const { parent: propAccess } = call; - const varDecl = isPropertyAccessExpression(propAccess) ? propAccess.parent : propAccess; - if (isExpressionStatement(varDecl) && isSourceFile(varDecl.parent)) { // `require("x");` as a statement - return true; - } - if (!isVariableDeclaration(varDecl)) { - return false; - } - const { parent: varDeclList } = varDecl; - if (varDeclList.kind !== SyntaxKind.VariableDeclarationList) { - return false; - } - const { parent: varStatement } = varDeclList; - return varStatement.kind === SyntaxKind.VariableStatement && varStatement.parent.kind === SyntaxKind.SourceFile; - } - - function getEditsForAction(context: RefactorContext, _actionName: string): RefactorEditInfo | undefined { - Debug.assertEqual(actionName, _actionName); - const { file, program } = context; - Debug.assert(isSourceFileJavaScript(file)); - const edits = textChanges.ChangeTracker.with(context, changes => { - const moduleExportsChangedToDefault = convertFileToEs6Module(file, program.getTypeChecker(), changes, program.getCompilerOptions().target); - if (moduleExportsChangedToDefault) { - for (const importingFile of program.getSourceFiles()) { - fixImportOfModuleExports(importingFile, file, changes); +namespace ts.codefix { + registerCodeFix({ + errorCodes: [Diagnostics.File_is_a_CommonJS_module_it_may_be_converted_to_an_ES6_module.code], + getCodeActions(context) { + const description = getLocaleSpecificMessage(Diagnostics.Convert_to_ES6_module); + const { sourceFile, program } = context; + const changes = textChanges.ChangeTracker.with(context, changes => { + const moduleExportsChangedToDefault = convertFileToEs6Module(sourceFile, program.getTypeChecker(), changes, program.getCompilerOptions().target); + if (moduleExportsChangedToDefault) { + for (const importingFile of program.getSourceFiles()) { + fixImportOfModuleExports(importingFile, sourceFile, changes); + } } - } - }); - return { edits, renameFilename: undefined, renameLocation: undefined }; - } + }); + // No support for fix-all since this applies to the whole file at once anyway. + return [{ description, changes, fixId: undefined }]; + }, + }); function fixImportOfModuleExports(importingFile: ts.SourceFile, exportingFile: ts.SourceFile, changes: textChanges.ChangeTracker) { for (const moduleSpecifier of importingFile.imports) { diff --git a/src/services/codefixes/fixes.ts b/src/services/codefixes/fixes.ts index 671f2251a32..24b726717a0 100644 --- a/src/services/codefixes/fixes.ts +++ b/src/services/codefixes/fixes.ts @@ -1,4 +1,5 @@ /// +/// /// /// /// diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 9f9bc959bf0..74a2aba76bb 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -663,7 +663,7 @@ namespace ts.codefix { const parent = token.parent; const isNodeOpeningLikeElement = isJsxOpeningLikeElement(parent); if ((isJsxOpeningLikeElement && (parent).tagName === token) || parent.kind === SyntaxKind.JsxOpeningFragment) { - umdSymbol = checker.resolveName(checker.getJsxNamespace(), + umdSymbol = checker.resolveName(checker.getJsxNamespace(parent), isNodeOpeningLikeElement ? (parent).tagName : parent, SymbolFlags.Value, /*excludeGlobals*/ false); } } diff --git a/src/services/completions.ts b/src/services/completions.ts index d07c2f494da..640cb5bedf3 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -943,7 +943,7 @@ namespace ts.Completions { getTypeScriptMemberSymbols(); } else if (isRightOfOpenTag) { - const tagSymbols = Debug.assertEachDefined(typeChecker.getJsxIntrinsicTagNames(), "getJsxIntrinsicTagNames() should all be defined"); + const tagSymbols = Debug.assertEachDefined(typeChecker.getJsxIntrinsicTagNamesAt(location), "getJsxIntrinsicTagNames() should all be defined"); if (tryGetGlobalSymbols()) { symbols = tagSymbols.concat(symbols.filter(s => !!(s.flags & (SymbolFlags.Value | SymbolFlags.Alias)))); } diff --git a/src/services/preProcess.ts b/src/services/preProcess.ts index a99683d45ef..fb138a87866 100644 --- a/src/services/preProcess.ts +++ b/src/services/preProcess.ts @@ -1,10 +1,17 @@ namespace ts { export function preProcessFile(sourceText: string, readImportFiles = true, detectJavaScriptImports = false): PreProcessedFileInfo { - const referencedFiles: FileReference[] = []; - const typeReferenceDirectives: FileReference[] = []; + const pragmaContext: PragmaContext = { + languageVersion: ScriptTarget.ES5, // controls weather the token scanner considers unicode identifiers or not - shouldn't matter, since we're only using it for trivia + pragmas: undefined, + checkJsDirective: undefined, + referencedFiles: [], + typeReferenceDirectives: [], + amdDependencies: [], + hasNoDefaultLib: undefined, + moduleName: undefined + }; const importedFiles: FileReference[] = []; let ambientExternalModules: { ref: FileReference, depth: number }[]; - let isNoDefaultLib = false; let braceNesting = 0; // assume that text represent an external module if it contains at least one top level import/export // ambient modules that are found inside external modules are interpreted as module augmentations @@ -21,25 +28,6 @@ namespace ts { return token; } - function processTripleSlashDirectives(): void { - const commentRanges = getLeadingCommentRanges(sourceText, 0); - forEach(commentRanges, commentRange => { - const comment = sourceText.substring(commentRange.pos, commentRange.end); - const referencePathMatchResult = getFileReferenceFromReferencePath(comment, commentRange); - if (referencePathMatchResult) { - isNoDefaultLib = referencePathMatchResult.isNoDefaultLib; - const fileReference = referencePathMatchResult.fileReference; - if (fileReference) { - const collection = referencePathMatchResult.isTypeReferenceDirective - ? typeReferenceDirectives - : referencedFiles; - - collection.push(fileReference); - } - } - }); - } - function getFileReference() { const fileName = scanner.getTokenValue(); const pos = scanner.getTokenPos(); @@ -328,7 +316,8 @@ namespace ts { if (readImportFiles) { processImports(); } - processTripleSlashDirectives(); + processCommentPragmas(pragmaContext, sourceText); + processPragmasIntoFields(pragmaContext, noop); if (externalModule) { // for external modules module all nested ambient modules are augmentations if (ambientExternalModules) { @@ -337,7 +326,7 @@ namespace ts { importedFiles.push(decl.ref); } } - return { referencedFiles, typeReferenceDirectives, importedFiles, isLibFile: isNoDefaultLib, ambientExternalModules: undefined }; + return { referencedFiles: pragmaContext.referencedFiles, typeReferenceDirectives: pragmaContext.typeReferenceDirectives, importedFiles, isLibFile: pragmaContext.hasNoDefaultLib, ambientExternalModules: undefined }; } else { // for global scripts ambient modules still can have augmentations - look for ambient modules with depth > 0 @@ -355,7 +344,7 @@ namespace ts { } } } - return { referencedFiles, typeReferenceDirectives, importedFiles, isLibFile: isNoDefaultLib, ambientExternalModules: ambientModuleNames }; + return { referencedFiles: pragmaContext.referencedFiles, typeReferenceDirectives: pragmaContext.typeReferenceDirectives, importedFiles, isLibFile: pragmaContext.hasNoDefaultLib, ambientExternalModules: ambientModuleNames }; } } } diff --git a/src/services/refactors/refactors.ts b/src/services/refactors/refactors.ts index 8b4561700d5..3858b198743 100644 --- a/src/services/refactors/refactors.ts +++ b/src/services/refactors/refactors.ts @@ -1,6 +1,5 @@ /// /// -/// /// /// /// diff --git a/src/services/services.ts b/src/services/services.ts index 624ca8c42bb..e29633a92e0 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -20,6 +20,7 @@ /// /// /// +/// /// /// /// @@ -651,6 +652,9 @@ namespace ts { public ambientModuleNames: string[]; public checkJsDirective: CheckJsDirective | undefined; public possiblyContainDynamicImport: boolean; + public pragmas: PragmaMap; + public localJsxFactory: EntityName; + public localJsxNamespace: __String; constructor(kind: SyntaxKind, pos: number, end: number) { super(kind, pos, end); @@ -1416,6 +1420,11 @@ namespace ts { return [...semanticDiagnostics, ...declarationDiagnostics]; } + function getSuggestionDiagnostics(fileName: string): Diagnostic[] { + synchronizeHostData(); + return computeSuggestionDiagnostics(getValidSourceFile(fileName)); + } + function getCompilerOptionsDiagnostics() { synchronizeHostData(); return [...program.getOptionsDiagnostics(cancellationToken), ...program.getGlobalDiagnostics(cancellationToken)]; @@ -2098,6 +2107,7 @@ namespace ts { cleanupSemanticCache, getSyntacticDiagnostics, getSemanticDiagnostics, + getSuggestionDiagnostics, getCompilerOptionsDiagnostics, getSyntacticClassifications, getSemanticClassifications, diff --git a/src/services/shims.ts b/src/services/shims.ts index 11e397f526a..5d3f82eb966 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -144,6 +144,7 @@ namespace ts { getSyntacticDiagnostics(fileName: string): string; getSemanticDiagnostics(fileName: string): string; + getSuggestionDiagnostics(fileName: string): string; getCompilerOptionsDiagnostics(): string; getSyntacticClassifications(fileName: string, start: number, length: number): string; @@ -581,7 +582,7 @@ namespace ts { } } - interface RealizedDiagnostic { + export interface RealizedDiagnostic { message: string; start: number; length: number; @@ -597,8 +598,7 @@ namespace ts { message: flattenDiagnosticMessageText(diagnostic.messageText, newLine), start: diagnostic.start, length: diagnostic.length, - /// TODO: no need for the tolowerCase call - category: DiagnosticCategory[diagnostic.category].toLowerCase(), + category: diagnosticCategoryName(diagnostic), code: diagnostic.code }; } @@ -716,6 +716,10 @@ namespace ts { }); } + public getSuggestionDiagnostics(fileName: string): string { + return this.forwardJSONCall(`getSuggestionDiagnostics('${fileName}')`, () => this.realizeDiagnostics(this.languageService.getSuggestionDiagnostics(fileName))); + } + public getCompilerOptionsDiagnostics(): string { return this.forwardJSONCall( "getCompilerOptionsDiagnostics()", diff --git a/src/services/suggestionDiagnostics.ts b/src/services/suggestionDiagnostics.ts new file mode 100644 index 00000000000..8cb26f74a01 --- /dev/null +++ b/src/services/suggestionDiagnostics.ts @@ -0,0 +1,8 @@ +/* @internal */ +namespace ts { + export function computeSuggestionDiagnostics(sourceFile: SourceFile): Diagnostic[] { + return sourceFile.commonJsModuleIndicator + ? [createDiagnosticForNode(sourceFile.commonJsModuleIndicator, Diagnostics.File_is_a_CommonJS_module_it_may_be_converted_to_an_ES6_module)] + : emptyArray; + } +} diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index 04a20bbbbb8..bc70106e530 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -212,11 +212,7 @@ namespace ts.textChanges { } /** Public for tests only. Other callers should use `ChangeTracker.with`. */ - constructor( - private readonly newLineCharacter: string, - private readonly formatContext: ts.formatting.FormatContext, - private readonly validator?: (text: NonFormattedText) => void) { - } + constructor(private readonly newLineCharacter: string, private readonly formatContext: ts.formatting.FormatContext) {} public deleteRange(sourceFile: SourceFile, range: TextRange) { this.changes.push({ kind: ChangeKind.Remove, sourceFile, range }); @@ -590,104 +586,83 @@ namespace ts.textChanges { }); } - public getChanges(): FileTextChanges[] { + /** + * Note: after calling this, the TextChanges object must be discarded! + * @param validate only for tests + * The reason we must validate as part of this method is that `getNonFormattedText` changes the node's positions, + * so we can only call this once and can't get the non-formatted text separately. + */ + public getChanges(validate?: ValidateNonFormattedText): FileTextChanges[] { this.finishInsertNodeAtClassStart(); - return group(this.changes, c => c.sourceFile.path).map(changesInFile => { + return changesToText.getTextChangesFromChanges(this.changes, this.newLineCharacter, this.formatContext, validate); + } + } + + export type ValidateNonFormattedText = (node: Node, text: string) => void; + + namespace changesToText { + export function getTextChangesFromChanges(changes: ReadonlyArray, newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText): FileTextChanges[] { + return group(changes, c => c.sourceFile.path).map(changesInFile => { const sourceFile = changesInFile[0].sourceFile; - const textChanges = ChangeTracker.normalize(changesInFile).map(c => - createTextChange(createTextSpanFromRange(c.range), this.computeNewText(c, sourceFile))); + // order changes by start position + const normalized = stableSort(changesInFile, (a, b) => a.range.pos - b.range.pos); + // verify that change intervals do not overlap, except possibly at end points. + for (let i = 0; i < normalized.length - 2; i++) { + Debug.assert(normalized[i].range.end <= normalized[i + 1].range.pos, "Changes overlap", () => + `${JSON.stringify(normalized[i].range)} and ${JSON.stringify(normalized[i + 1].range)}`); + } + const textChanges = normalized.map(c => + createTextChange(createTextSpanFromRange(c.range), computeNewText(c, sourceFile, newLineCharacter, formatContext, validate))); return { fileName: sourceFile.fileName, textChanges }; }); } - private computeNewText(change: Change, sourceFile: SourceFile): string { + function computeNewText(change: Change, sourceFile: SourceFile, newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText): string { if (change.kind === ChangeKind.Remove) { - // deletion case return ""; } - const options = change.options || {}; - let text: string; - const pos = change.range.pos; - const posStartsLine = getLineStartPositionForPosition(pos, sourceFile) === pos; - if (change.kind === ChangeKind.ReplaceWithMultipleNodes) { - const lastIndex = change.nodes.length - 1; - const parts = change.nodes.map((n, index) => { - const formatted = this.getFormattedTextOfNode(n, sourceFile, pos, options); - return index === lastIndex || endsWith(formatted, this.newLineCharacter) - ? formatted - : (formatted + this.newLineCharacter); - }); - text = parts.join(""); - } - else { - Debug.assert(change.kind === ChangeKind.ReplaceWithSingleNode, "change.kind === ReplaceWithSingleNode"); - text = this.getFormattedTextOfNode(change.node, sourceFile, pos, options); - } + const { options = {}, range: { pos } } = change; + const format = (n: Node) => getFormattedTextOfNode(n, sourceFile, pos, options, newLineCharacter, formatContext, validate); + const text = change.kind === ChangeKind.ReplaceWithMultipleNodes + ? change.nodes.map(n => removeSuffix(format(n), newLineCharacter)).join(newLineCharacter) + : format(change.node); // strip initial indentation (spaces or tabs) if text will be inserted in the middle of the line - text = (posStartsLine || options.indentation !== undefined) ? text : text.replace(/^\s+/, ""); - return (options.prefix || "") + text + (options.suffix || ""); + const noIndent = (options.indentation !== undefined || getLineStartPositionForPosition(pos, sourceFile) === pos) ? text : text.replace(/^\s+/, ""); + return (options.prefix || "") + noIndent + (options.suffix || ""); } - private getFormattedTextOfNode(node: Node, sourceFile: SourceFile, pos: number, options: ChangeNodeOptions): string { - const nonformattedText = getNonformattedText(node, sourceFile, this.newLineCharacter); - if (this.validator) { - this.validator(nonformattedText); - } - - const { options: formatOptions } = this.formatContext; - const posStartsLine = getLineStartPositionForPosition(pos, sourceFile) === pos; - + /** Note: this may mutate `nodeIn`. */ + function getFormattedTextOfNode(nodeIn: Node, sourceFile: SourceFile, pos: number, options: ChangeNodeOptions, newLineCharacter: string, formatContext: formatting.FormatContext, validate: ValidateNonFormattedText): string { + const { node, text } = getNonformattedText(nodeIn, sourceFile, newLineCharacter); + if (validate) validate(node, text); + const { options: formatOptions } = formatContext; const initialIndentation = options.indentation !== undefined ? options.indentation : (options.useIndentationFromFile !== false) - ? formatting.SmartIndenter.getIndentation(pos, sourceFile, formatOptions, posStartsLine || (options.prefix === this.newLineCharacter)) + ? formatting.SmartIndenter.getIndentation(pos, sourceFile, formatOptions, options.prefix === newLineCharacter || getLineStartPositionForPosition(pos, sourceFile) === pos) : 0; const delta = options.delta !== undefined ? options.delta - : formatting.SmartIndenter.shouldIndentChildNode(node) + : formatting.SmartIndenter.shouldIndentChildNode(nodeIn) ? (formatOptions.indentSize || 0) : 0; - - return applyFormatting(nonformattedText, sourceFile, initialIndentation, delta, this.formatContext); + const file: SourceFileLike = { text, getLineAndCharacterOfPosition(pos) { return getLineAndCharacterOfPosition(this, pos); } }; + const changes = formatting.formatNodeGivenIndentation(node, file, sourceFile.languageVariant, initialIndentation, delta, formatContext); + return applyChanges(text, changes); } - private static normalize(changes: ReadonlyArray): ReadonlyArray { - // order changes by start position - const normalized = stableSort(changes, (a, b) => a.range.pos - b.range.pos); - // verify that change intervals do not overlap, except possibly at end points. - for (let i = 0; i < normalized.length - 2; i++) { - Debug.assert(normalized[i].range.end <= normalized[i + 1].range.pos); - } - return normalized; + /** Note: output node may be mutated input node. */ + function getNonformattedText(node: Node, sourceFile: SourceFile | undefined, newLineCharacter: string): { text: string, node: Node } { + const writer = new Writer(newLineCharacter); + const newLine = newLineCharacter === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed; + createPrinter({ newLine }, writer).writeNode(EmitHint.Unspecified, node, sourceFile, writer); + return { text: writer.getText(), node: assignPositionsToNode(node) }; } } - export interface NonFormattedText { - readonly text: string; - readonly node: Node; - } - - function getNonformattedText(node: Node, sourceFile: SourceFile | undefined, newLine: string): NonFormattedText { - const writer = new Writer(newLine); - const printer = createPrinter({ newLine: newLine === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed }, writer); - printer.writeNode(EmitHint.Unspecified, node, sourceFile, writer); - return { text: writer.getText(), node: assignPositionsToNode(node) }; - } - - function applyFormatting(nonFormattedText: NonFormattedText, sourceFile: SourceFile, initialIndentation: number, delta: number, formatContext: ts.formatting.FormatContext) { - const lineMap = computeLineStarts(nonFormattedText.text); - const file: SourceFileLike = { - text: nonFormattedText.text, - lineMap, - getLineAndCharacterOfPosition: pos => computeLineAndCharacterOfPosition(lineMap, pos) - }; - const changes = formatting.formatNodeGivenIndentation(nonFormattedText.node, file, sourceFile.languageVariant, initialIndentation, delta, formatContext); - return applyChanges(nonFormattedText.text, changes); - } - export function applyChanges(text: string, changes: TextChange[]): string { for (let i = changes.length - 1; i >= 0; i--) { const change = changes[i]; diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json index bbd88a1a004..686c3357bc3 100644 --- a/src/services/tsconfig.json +++ b/src/services/tsconfig.json @@ -70,6 +70,7 @@ "semver.ts", "shims.ts", "signatureHelp.ts", + "suggestionDiagnostics.ts", "symbolDisplay.ts", "textChanges.ts", "refactorProvider.ts", diff --git a/src/services/types.ts b/src/services/types.ts index b67c2569f27..dba10960cdf 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -223,6 +223,7 @@ namespace ts { getSyntacticDiagnostics(fileName: string): Diagnostic[]; getSemanticDiagnostics(fileName: string): Diagnostic[]; + getSuggestionDiagnostics(fileName: string): Diagnostic[]; // TODO: Rename this to getProgramDiagnostics to better indicate that these are any // diagnostics present for the program level, and not just 'options' diagnostics. diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 52320578833..9a8f0188147 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -1811,7 +1811,7 @@ declare namespace ts { getAliasedSymbol(symbol: Symbol): Symbol; getExportsOfModule(moduleSymbol: Symbol): Symbol[]; getAllAttributesTypeFromJsxOpeningLikeElement(elementNode: JsxOpeningLikeElement): Type | undefined; - getJsxIntrinsicTagNames(): Symbol[]; + getJsxIntrinsicTagNamesAt(location: Node): Symbol[]; isOptionalParameter(node: ParameterDeclaration): boolean; getAmbientModules(): Symbol[]; tryGetMemberInModuleExports(memberName: string, moduleSymbol: Symbol): Symbol | undefined; @@ -2276,7 +2276,8 @@ declare namespace ts { enum DiagnosticCategory { Warning = 0, Error = 1, - Message = 2, + Suggestion = 2, + Message = 3, } enum ModuleResolutionKind { Classic = 1, @@ -4068,6 +4069,7 @@ declare namespace ts { cleanupSemanticCache(): void; getSyntacticDiagnostics(fileName: string): Diagnostic[]; getSemanticDiagnostics(fileName: string): Diagnostic[]; + getSuggestionDiagnostics(fileName: string): Diagnostic[]; getCompilerOptionsDiagnostics(): Diagnostic[]; /** * @deprecated Use getEncodedSyntacticClassifications instead. @@ -5038,6 +5040,7 @@ declare namespace ts.server.protocol { GeterrForProject = "geterrForProject", SemanticDiagnosticsSync = "semanticDiagnosticsSync", SyntacticDiagnosticsSync = "syntacticDiagnosticsSync", + SuggestionDiagnosticsSync = "suggestionDiagnosticsSync", NavBar = "navbar", Navto = "navto", NavTree = "navtree", @@ -6560,6 +6563,12 @@ declare namespace ts.server.protocol { interface SemanticDiagnosticsSyncResponse extends Response { body?: Diagnostic[] | DiagnosticWithLinePosition[]; } + interface SuggestionDiagnosticsSyncRequest extends FileRequest { + command: CommandTypes.SuggestionDiagnosticsSync; + arguments: SuggestionDiagnosticsSyncRequestArgs; + } + type SuggestionDiagnosticsSyncRequestArgs = SemanticDiagnosticsSyncRequestArgs; + type SuggestionDiagnosticsSyncResponse = SemanticDiagnosticsSyncResponse; /** * Synchronous request for syntactic diagnostics of one file. */ @@ -6656,7 +6665,7 @@ declare namespace ts.server.protocol { */ text: string; /** - * The category of the diagnostic message, e.g. "error" vs. "warning" + * The category of the diagnostic message, e.g. "error", "warning", or "suggestion". */ category: string; /** @@ -6684,8 +6693,9 @@ declare namespace ts.server.protocol { */ diagnostics: Diagnostic[]; } + type DiagnosticEventKind = "semanticDiag" | "syntaxDiag" | "suggestionDiag"; /** - * Event message for "syntaxDiag" and "semanticDiag" event types. + * Event message for DiagnosticEventKind event types. * These events provide syntactic and semantic errors for a file. */ interface DiagnosticEvent extends Event { @@ -7220,6 +7230,8 @@ declare namespace ts.server { private doOutput(info, cmdName, reqSeq, success, message?); private semanticCheck(file, project); private syntacticCheck(file, project); + private infoCheck(file, project); + private sendDiagnosticsEvent(file, project, diagnostics, kind); private updateErrorCheck(next, checkList, ms, requireOpen?); private cleanProjects(caption, projects); private cleanup(); @@ -7240,6 +7252,7 @@ declare namespace ts.server { private getOccurrences(args); private getSyntacticDiagnosticsSync(args); private getSemanticDiagnosticsSync(args); + private getSuggestionDiagnosticsSync(args); private getDocumentHighlights(args, simplifiedResult); private setCompilerOptionsForInferredProjects(args); private getProjectInfo(args); diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index dda17b0666c..76e80978a52 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -1811,7 +1811,7 @@ declare namespace ts { getAliasedSymbol(symbol: Symbol): Symbol; getExportsOfModule(moduleSymbol: Symbol): Symbol[]; getAllAttributesTypeFromJsxOpeningLikeElement(elementNode: JsxOpeningLikeElement): Type | undefined; - getJsxIntrinsicTagNames(): Symbol[]; + getJsxIntrinsicTagNamesAt(location: Node): Symbol[]; isOptionalParameter(node: ParameterDeclaration): boolean; getAmbientModules(): Symbol[]; tryGetMemberInModuleExports(memberName: string, moduleSymbol: Symbol): Symbol | undefined; @@ -2276,7 +2276,8 @@ declare namespace ts { enum DiagnosticCategory { Warning = 0, Error = 1, - Message = 2, + Suggestion = 2, + Message = 3, } enum ModuleResolutionKind { Classic = 1, @@ -4320,6 +4321,7 @@ declare namespace ts { cleanupSemanticCache(): void; getSyntacticDiagnostics(fileName: string): Diagnostic[]; getSemanticDiagnostics(fileName: string): Diagnostic[]; + getSuggestionDiagnostics(fileName: string): Diagnostic[]; getCompilerOptionsDiagnostics(): Diagnostic[]; /** * @deprecated Use getEncodedSyntacticClassifications instead. diff --git a/tests/baselines/reference/cacheResolutions.trace.json b/tests/baselines/reference/cacheResolutions.trace.json index bf3653b489a..e23322299e6 100644 --- a/tests/baselines/reference/cacheResolutions.trace.json +++ b/tests/baselines/reference/cacheResolutions.trace.json @@ -27,9 +27,9 @@ "File '/tslib.jsx' does not exist.", "======== Module name 'tslib' was not resolved. ========", "======== Resolving module 'tslib' from '/a/b/c/lib1.ts'. ========", - "Resolution for module 'tslib' was found in cache.", + "Resolution for module 'tslib' was found in cache from location '/a/b/c'.", "======== Module name 'tslib' was not resolved. ========", "======== Resolving module 'tslib' from '/a/b/c/lib2.ts'. ========", - "Resolution for module 'tslib' was found in cache.", + "Resolution for module 'tslib' was found in cache from location '/a/b/c'.", "======== Module name 'tslib' was not resolved. ========" ] \ No newline at end of file diff --git a/tests/baselines/reference/cachedModuleResolution1.trace.json b/tests/baselines/reference/cachedModuleResolution1.trace.json index c9f40c56796..48997f9784d 100644 --- a/tests/baselines/reference/cachedModuleResolution1.trace.json +++ b/tests/baselines/reference/cachedModuleResolution1.trace.json @@ -13,7 +13,7 @@ "======== Resolving module 'foo' from '/a/b/c/lib.ts'. ========", "Explicitly specified module resolution kind: 'NodeJs'.", "Loading module 'foo' from 'node_modules' folder, target file type 'TypeScript'.", - "Resolution for module 'foo' was found in cache.", + "Resolution for module 'foo' was found in cache from location '/a/b/c'.", "Resolving real path for '/a/b/node_modules/foo.d.ts', result '/a/b/node_modules/foo.d.ts'.", "======== Module name 'foo' was successfully resolved to '/a/b/node_modules/foo.d.ts'. ========" ] \ No newline at end of file diff --git a/tests/baselines/reference/cachedModuleResolution2.trace.json b/tests/baselines/reference/cachedModuleResolution2.trace.json index a7fc2414f03..197d3a708e3 100644 --- a/tests/baselines/reference/cachedModuleResolution2.trace.json +++ b/tests/baselines/reference/cachedModuleResolution2.trace.json @@ -13,7 +13,7 @@ "Loading module 'foo' from 'node_modules' folder, target file type 'TypeScript'.", "Directory '/a/b/c/d/e/node_modules' does not exist, skipping all lookups in it.", "Directory '/a/b/c/d/node_modules' does not exist, skipping all lookups in it.", - "Resolution for module 'foo' was found in cache.", + "Resolution for module 'foo' was found in cache from location '/a/b/c'.", "Resolving real path for '/a/b/node_modules/foo.d.ts', result '/a/b/node_modules/foo.d.ts'.", "======== Module name 'foo' was successfully resolved to '/a/b/node_modules/foo.d.ts'. ========" ] \ No newline at end of file diff --git a/tests/baselines/reference/cachedModuleResolution3.trace.json b/tests/baselines/reference/cachedModuleResolution3.trace.json index 6cbab2e0796..2f401df9ef5 100644 --- a/tests/baselines/reference/cachedModuleResolution3.trace.json +++ b/tests/baselines/reference/cachedModuleResolution3.trace.json @@ -16,6 +16,6 @@ "======== Module name 'foo' was successfully resolved to '/a/b/foo.d.ts'. ========", "======== Resolving module 'foo' from '/a/b/c/lib.ts'. ========", "Explicitly specified module resolution kind: 'Classic'.", - "Resolution for module 'foo' was found in cache.", + "Resolution for module 'foo' was found in cache from location '/a/b/c'.", "======== Module name 'foo' was successfully resolved to '/a/b/foo.d.ts'. ========" ] \ No newline at end of file diff --git a/tests/baselines/reference/cachedModuleResolution4.trace.json b/tests/baselines/reference/cachedModuleResolution4.trace.json index c100c0c3814..7771f99ca9f 100644 --- a/tests/baselines/reference/cachedModuleResolution4.trace.json +++ b/tests/baselines/reference/cachedModuleResolution4.trace.json @@ -16,6 +16,6 @@ "File '/a/b/c/d/foo.ts' does not exist.", "File '/a/b/c/d/foo.tsx' does not exist.", "File '/a/b/c/d/foo.d.ts' does not exist.", - "Resolution for module 'foo' was found in cache.", + "Resolution for module 'foo' was found in cache from location '/a/b/c'.", "======== Module name 'foo' was successfully resolved to '/a/b/foo.d.ts'. ========" ] \ No newline at end of file diff --git a/tests/baselines/reference/cachedModuleResolution5.trace.json b/tests/baselines/reference/cachedModuleResolution5.trace.json index b09cc7a35be..4438192b155 100644 --- a/tests/baselines/reference/cachedModuleResolution5.trace.json +++ b/tests/baselines/reference/cachedModuleResolution5.trace.json @@ -13,7 +13,7 @@ "======== Resolving module 'foo' from '/a/b/lib.ts'. ========", "Explicitly specified module resolution kind: 'NodeJs'.", "Loading module 'foo' from 'node_modules' folder, target file type 'TypeScript'.", - "Resolution for module 'foo' was found in cache.", + "Resolution for module 'foo' was found in cache from location '/a/b'.", "Resolving real path for '/a/b/node_modules/foo.d.ts', result '/a/b/node_modules/foo.d.ts'.", "======== Module name 'foo' was successfully resolved to '/a/b/node_modules/foo.d.ts'. ========" ] \ No newline at end of file diff --git a/tests/baselines/reference/cachedModuleResolution6.trace.json b/tests/baselines/reference/cachedModuleResolution6.trace.json index 50c1c15b3e1..5d43bb94dd2 100644 --- a/tests/baselines/reference/cachedModuleResolution6.trace.json +++ b/tests/baselines/reference/cachedModuleResolution6.trace.json @@ -19,6 +19,6 @@ "======== Resolving module 'foo' from '/a/b/c/lib.ts'. ========", "Explicitly specified module resolution kind: 'NodeJs'.", "Loading module 'foo' from 'node_modules' folder, target file type 'TypeScript'.", - "Resolution for module 'foo' was found in cache.", + "Resolution for module 'foo' was found in cache from location '/a/b/c'.", "======== Module name 'foo' was not resolved. ========" ] \ No newline at end of file diff --git a/tests/baselines/reference/cachedModuleResolution7.trace.json b/tests/baselines/reference/cachedModuleResolution7.trace.json index fa1db9d115e..49fc1e75b0c 100644 --- a/tests/baselines/reference/cachedModuleResolution7.trace.json +++ b/tests/baselines/reference/cachedModuleResolution7.trace.json @@ -17,6 +17,6 @@ "Loading module 'foo' from 'node_modules' folder, target file type 'TypeScript'.", "Directory '/a/b/c/d/e/node_modules' does not exist, skipping all lookups in it.", "Directory '/a/b/c/d/node_modules' does not exist, skipping all lookups in it.", - "Resolution for module 'foo' was found in cache.", + "Resolution for module 'foo' was found in cache from location '/a/b/c'.", "======== Module name 'foo' was not resolved. ========" ] \ No newline at end of file diff --git a/tests/baselines/reference/cachedModuleResolution8.trace.json b/tests/baselines/reference/cachedModuleResolution8.trace.json index e5241278349..9b7c37c8568 100644 --- a/tests/baselines/reference/cachedModuleResolution8.trace.json +++ b/tests/baselines/reference/cachedModuleResolution8.trace.json @@ -40,6 +40,6 @@ "======== Module name 'foo' was not resolved. ========", "======== Resolving module 'foo' from '/a/b/c/lib.ts'. ========", "Explicitly specified module resolution kind: 'Classic'.", - "Resolution for module 'foo' was found in cache.", + "Resolution for module 'foo' was found in cache from location '/a/b/c'.", "======== Module name 'foo' was not resolved. ========" ] \ No newline at end of file diff --git a/tests/baselines/reference/cachedModuleResolution9.trace.json b/tests/baselines/reference/cachedModuleResolution9.trace.json index bd148cc7ee2..b07e32abf5e 100644 --- a/tests/baselines/reference/cachedModuleResolution9.trace.json +++ b/tests/baselines/reference/cachedModuleResolution9.trace.json @@ -34,6 +34,6 @@ "File '/a/b/c/d/foo.ts' does not exist.", "File '/a/b/c/d/foo.tsx' does not exist.", "File '/a/b/c/d/foo.d.ts' does not exist.", - "Resolution for module 'foo' was found in cache.", + "Resolution for module 'foo' was found in cache from location '/a/b/c'.", "======== Module name 'foo' was not resolved. ========" ] \ No newline at end of file diff --git a/tests/baselines/reference/esModuleInterop.js b/tests/baselines/reference/esModuleInterop.js index 9a04ab01be6..c5cc264fe71 100644 --- a/tests/baselines/reference/esModuleInterop.js +++ b/tests/baselines/reference/esModuleInterop.js @@ -22,14 +22,14 @@ fs; "use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; -} +}; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; -} +}; exports.__esModule = true; var hybrid_1 = require("./hybrid"); var path_1 = __importDefault(require("./path")); diff --git a/tests/baselines/reference/esModuleInteropImportCall.js b/tests/baselines/reference/esModuleInteropImportCall.js index 2aa681ded7f..d7bf027b001 100644 --- a/tests/baselines/reference/esModuleInteropImportCall.js +++ b/tests/baselines/reference/esModuleInteropImportCall.js @@ -17,7 +17,7 @@ var __importStar = (this && this.__importStar) || function (mod) { if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; -} +}; Promise.resolve().then(function () { return __importStar(require("./foo")); }).then(function (f) { f["default"]; }); diff --git a/tests/baselines/reference/esModuleInteropImportNamespace.js b/tests/baselines/reference/esModuleInteropImportNamespace.js index 605976faaaa..74449347623 100644 --- a/tests/baselines/reference/esModuleInteropImportNamespace.js +++ b/tests/baselines/reference/esModuleInteropImportNamespace.js @@ -18,7 +18,7 @@ var __importStar = (this && this.__importStar) || function (mod) { if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; -} +}; exports.__esModule = true; var foo = __importStar(require("./foo")); foo["default"]; diff --git a/tests/baselines/reference/esModuleInteropNamedDefaultImports.js b/tests/baselines/reference/esModuleInteropNamedDefaultImports.js index d3a804b5e4c..f8181c59550 100644 --- a/tests/baselines/reference/esModuleInteropNamedDefaultImports.js +++ b/tests/baselines/reference/esModuleInteropNamedDefaultImports.js @@ -31,14 +31,14 @@ exports.Bar = Bar; "use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; -} +}; var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; -} +}; exports.__esModule = true; var mod_1 = __importDefault(require("./mod")); var mod_2 = __importDefault(require("./mod")); diff --git a/tests/baselines/reference/esModuleIntersectionCrash.js b/tests/baselines/reference/esModuleIntersectionCrash.js index a8f6ed5c014..27de446e93c 100644 --- a/tests/baselines/reference/esModuleIntersectionCrash.js +++ b/tests/baselines/reference/esModuleIntersectionCrash.js @@ -20,7 +20,7 @@ var __importStar = (this && this.__importStar) || function (mod) { if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; result["default"] = mod; return result; -} +}; exports.__esModule = true; var mod = __importStar(require("./mod")); mod.a; diff --git a/tests/baselines/reference/indirectUniqueSymbolDeclarationEmit.js b/tests/baselines/reference/indirectUniqueSymbolDeclarationEmit.js new file mode 100644 index 00000000000..d3f312ae82e --- /dev/null +++ b/tests/baselines/reference/indirectUniqueSymbolDeclarationEmit.js @@ -0,0 +1,23 @@ +//// [indirectUniqueSymbolDeclarationEmit.ts] +export const x = Symbol(); +export const y = Symbol(); +declare function rand(): boolean; +export function f() { + return rand() ? x : y; +} + +//// [indirectUniqueSymbolDeclarationEmit.js] +"use strict"; +exports.__esModule = true; +exports.x = Symbol(); +exports.y = Symbol(); +function f() { + return rand() ? exports.x : exports.y; +} +exports.f = f; + + +//// [indirectUniqueSymbolDeclarationEmit.d.ts] +export declare const x: unique symbol; +export declare const y: unique symbol; +export declare function f(): typeof x | typeof y; diff --git a/tests/baselines/reference/indirectUniqueSymbolDeclarationEmit.symbols b/tests/baselines/reference/indirectUniqueSymbolDeclarationEmit.symbols new file mode 100644 index 00000000000..9f205084ecb --- /dev/null +++ b/tests/baselines/reference/indirectUniqueSymbolDeclarationEmit.symbols @@ -0,0 +1,20 @@ +=== tests/cases/compiler/indirectUniqueSymbolDeclarationEmit.ts === +export const x = Symbol(); +>x : Symbol(x, Decl(indirectUniqueSymbolDeclarationEmit.ts, 0, 12)) +>Symbol : Symbol(Symbol, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --)) + +export const y = Symbol(); +>y : Symbol(y, Decl(indirectUniqueSymbolDeclarationEmit.ts, 1, 12)) +>Symbol : Symbol(Symbol, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --)) + +declare function rand(): boolean; +>rand : Symbol(rand, Decl(indirectUniqueSymbolDeclarationEmit.ts, 1, 26)) + +export function f() { +>f : Symbol(f, Decl(indirectUniqueSymbolDeclarationEmit.ts, 2, 33)) + + return rand() ? x : y; +>rand : Symbol(rand, Decl(indirectUniqueSymbolDeclarationEmit.ts, 1, 26)) +>x : Symbol(x, Decl(indirectUniqueSymbolDeclarationEmit.ts, 0, 12)) +>y : Symbol(y, Decl(indirectUniqueSymbolDeclarationEmit.ts, 1, 12)) +} diff --git a/tests/baselines/reference/indirectUniqueSymbolDeclarationEmit.types b/tests/baselines/reference/indirectUniqueSymbolDeclarationEmit.types new file mode 100644 index 00000000000..f50010d8f53 --- /dev/null +++ b/tests/baselines/reference/indirectUniqueSymbolDeclarationEmit.types @@ -0,0 +1,24 @@ +=== tests/cases/compiler/indirectUniqueSymbolDeclarationEmit.ts === +export const x = Symbol(); +>x : unique symbol +>Symbol() : unique symbol +>Symbol : SymbolConstructor + +export const y = Symbol(); +>y : unique symbol +>Symbol() : unique symbol +>Symbol : SymbolConstructor + +declare function rand(): boolean; +>rand : () => boolean + +export function f() { +>f : () => unique symbol | unique symbol + + return rand() ? x : y; +>rand() ? x : y : unique symbol | unique symbol +>rand() : boolean +>rand : () => boolean +>x : unique symbol +>y : unique symbol +} diff --git a/tests/baselines/reference/inferredNonidentifierTypesGetQuotes.js b/tests/baselines/reference/inferredNonidentifierTypesGetQuotes.js new file mode 100644 index 00000000000..e9ce8e56d1f --- /dev/null +++ b/tests/baselines/reference/inferredNonidentifierTypesGetQuotes.js @@ -0,0 +1,22 @@ +//// [inferredNonidentifierTypesGetQuotes.ts] +var x = [{ "a-b": "string" }, {}]; + +var y = [{ ["a-b"]: "string" }, {}]; + +//// [inferredNonidentifierTypesGetQuotes.js] +var x = [{ "a-b": "string" }, {}]; +var y = [(_a = {}, _a["a-b"] = "string", _a), {}]; +var _a; + + +//// [inferredNonidentifierTypesGetQuotes.d.ts] +declare var x: ({ + "a-b": string; +} | { + "a-b"?: undefined; +})[]; +declare var y: ({ + ["a-b"]: string; +} | { + "a-b"?: undefined; +})[]; diff --git a/tests/baselines/reference/inferredNonidentifierTypesGetQuotes.symbols b/tests/baselines/reference/inferredNonidentifierTypesGetQuotes.symbols new file mode 100644 index 00000000000..f37063dcee5 --- /dev/null +++ b/tests/baselines/reference/inferredNonidentifierTypesGetQuotes.symbols @@ -0,0 +1,10 @@ +=== tests/cases/compiler/inferredNonidentifierTypesGetQuotes.ts === +var x = [{ "a-b": "string" }, {}]; +>x : Symbol(x, Decl(inferredNonidentifierTypesGetQuotes.ts, 0, 3)) +>"a-b" : Symbol("a-b", Decl(inferredNonidentifierTypesGetQuotes.ts, 0, 10)) + +var y = [{ ["a-b"]: "string" }, {}]; +>y : Symbol(y, Decl(inferredNonidentifierTypesGetQuotes.ts, 2, 3)) +>["a-b"] : Symbol(["a-b"], Decl(inferredNonidentifierTypesGetQuotes.ts, 2, 10)) +>"a-b" : Symbol(["a-b"], Decl(inferredNonidentifierTypesGetQuotes.ts, 2, 10)) + diff --git a/tests/baselines/reference/inferredNonidentifierTypesGetQuotes.types b/tests/baselines/reference/inferredNonidentifierTypesGetQuotes.types new file mode 100644 index 00000000000..361b550952a --- /dev/null +++ b/tests/baselines/reference/inferredNonidentifierTypesGetQuotes.types @@ -0,0 +1,18 @@ +=== tests/cases/compiler/inferredNonidentifierTypesGetQuotes.ts === +var x = [{ "a-b": "string" }, {}]; +>x : ({ "a-b": string; } | { "a-b"?: undefined; })[] +>[{ "a-b": "string" }, {}] : ({ "a-b": string; } | {})[] +>{ "a-b": "string" } : { "a-b": string; } +>"a-b" : string +>"string" : "string" +>{} : {} + +var y = [{ ["a-b"]: "string" }, {}]; +>y : ({ ["a-b"]: string; } | { "a-b"?: undefined; })[] +>[{ ["a-b"]: "string" }, {}] : ({ ["a-b"]: string; } | {})[] +>{ ["a-b"]: "string" } : { ["a-b"]: string; } +>["a-b"] : string +>"a-b" : "a-b" +>"string" : "string" +>{} : {} + diff --git a/tests/baselines/reference/inlineJsxFactoryDeclarations.js b/tests/baselines/reference/inlineJsxFactoryDeclarations.js new file mode 100644 index 00000000000..958c43af83f --- /dev/null +++ b/tests/baselines/reference/inlineJsxFactoryDeclarations.js @@ -0,0 +1,74 @@ +//// [tests/cases/conformance/jsx/inline/inlineJsxFactoryDeclarations.tsx] //// + +//// [renderer.d.ts] +declare global { + namespace JSX { + interface IntrinsicElements { + [e: string]: any; + } + } +} +export function dom(): void; +export function otherdom(): void; +export function createElement(): void; +export { dom as default }; +//// [otherreacty.tsx] +/** @jsx React.createElement */ +import * as React from "./renderer"; + +//// [other.tsx] +/** @jsx h */ +import { dom as h } from "./renderer" +export const prerendered = ; +//// [othernoalias.tsx] +/** @jsx otherdom */ +import { otherdom } from "./renderer" +export const prerendered2 = ; +//// [reacty.tsx] +import React from "./renderer" +export const prerendered3 = ; + +//// [index.tsx] +/** @jsx dom */ +import { dom } from "./renderer" + +export * from "./other"; +export * from "./othernoalias"; +export * from "./reacty"; + + +//// [otherreacty.js] +"use strict"; +exports.__esModule = true; +/** @jsx React.createElement */ +var React = require("./renderer"); +React.createElement("h", null); +//// [other.js] +"use strict"; +exports.__esModule = true; +/** @jsx h */ +var renderer_1 = require("./renderer"); +exports.prerendered = renderer_1.dom("h", null); +//// [othernoalias.js] +"use strict"; +exports.__esModule = true; +/** @jsx otherdom */ +var renderer_1 = require("./renderer"); +exports.prerendered2 = renderer_1.otherdom("h", null); +//// [reacty.js] +"use strict"; +exports.__esModule = true; +var renderer_1 = require("./renderer"); +exports.prerendered3 = renderer_1["default"].createElement("h", null); +//// [index.js] +"use strict"; +function __export(m) { + for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; +} +exports.__esModule = true; +/** @jsx dom */ +var renderer_1 = require("./renderer"); +renderer_1.dom("h", null); +__export(require("./other")); +__export(require("./othernoalias")); +__export(require("./reacty")); diff --git a/tests/baselines/reference/inlineJsxFactoryDeclarations.symbols b/tests/baselines/reference/inlineJsxFactoryDeclarations.symbols new file mode 100644 index 00000000000..43a53ec9df2 --- /dev/null +++ b/tests/baselines/reference/inlineJsxFactoryDeclarations.symbols @@ -0,0 +1,80 @@ +=== tests/cases/conformance/jsx/inline/renderer.d.ts === +declare global { +>global : Symbol(global, Decl(renderer.d.ts, 0, 0)) + + namespace JSX { +>JSX : Symbol(JSX, Decl(renderer.d.ts, 0, 16)) + + interface IntrinsicElements { +>IntrinsicElements : Symbol(IntrinsicElements, Decl(renderer.d.ts, 1, 19)) + + [e: string]: any; +>e : Symbol(e, Decl(renderer.d.ts, 3, 13)) + } + } +} +export function dom(): void; +>dom : Symbol(dom, Decl(renderer.d.ts, 6, 1)) + +export function otherdom(): void; +>otherdom : Symbol(otherdom, Decl(renderer.d.ts, 7, 28)) + +export function createElement(): void; +>createElement : Symbol(createElement, Decl(renderer.d.ts, 8, 33)) + +export { dom as default }; +>dom : Symbol(default, Decl(renderer.d.ts, 10, 8)) +>default : Symbol(default, Decl(renderer.d.ts, 10, 8)) + +=== tests/cases/conformance/jsx/inline/otherreacty.tsx === +/** @jsx React.createElement */ +import * as React from "./renderer"; +>React : Symbol(React, Decl(otherreacty.tsx, 1, 6)) + + +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) + +=== tests/cases/conformance/jsx/inline/other.tsx === +/** @jsx h */ +import { dom as h } from "./renderer" +>dom : Symbol(h, Decl(other.tsx, 1, 8)) +>h : Symbol(h, Decl(other.tsx, 1, 8)) + +export const prerendered = ; +>prerendered : Symbol(prerendered, Decl(other.tsx, 2, 12)) +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) + +=== tests/cases/conformance/jsx/inline/othernoalias.tsx === +/** @jsx otherdom */ +import { otherdom } from "./renderer" +>otherdom : Symbol(otherdom, Decl(othernoalias.tsx, 1, 8)) + +export const prerendered2 = ; +>prerendered2 : Symbol(prerendered2, Decl(othernoalias.tsx, 2, 12)) +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) + +=== tests/cases/conformance/jsx/inline/reacty.tsx === +import React from "./renderer" +>React : Symbol(React, Decl(reacty.tsx, 0, 6)) + +export const prerendered3 = ; +>prerendered3 : Symbol(prerendered3, Decl(reacty.tsx, 1, 12)) +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) + +=== tests/cases/conformance/jsx/inline/index.tsx === +/** @jsx dom */ +import { dom } from "./renderer" +>dom : Symbol(dom, Decl(index.tsx, 1, 8)) + + +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) + +export * from "./other"; +export * from "./othernoalias"; +export * from "./reacty"; + diff --git a/tests/baselines/reference/inlineJsxFactoryDeclarations.types b/tests/baselines/reference/inlineJsxFactoryDeclarations.types new file mode 100644 index 00000000000..13c382fe45c --- /dev/null +++ b/tests/baselines/reference/inlineJsxFactoryDeclarations.types @@ -0,0 +1,85 @@ +=== tests/cases/conformance/jsx/inline/renderer.d.ts === +declare global { +>global : any + + namespace JSX { +>JSX : any + + interface IntrinsicElements { +>IntrinsicElements : IntrinsicElements + + [e: string]: any; +>e : string + } + } +} +export function dom(): void; +>dom : () => void + +export function otherdom(): void; +>otherdom : () => void + +export function createElement(): void; +>createElement : () => void + +export { dom as default }; +>dom : () => void +>default : () => void + +=== tests/cases/conformance/jsx/inline/otherreacty.tsx === +/** @jsx React.createElement */ +import * as React from "./renderer"; +>React : typeof React + + +> : any +>h : any +>h : any + +=== tests/cases/conformance/jsx/inline/other.tsx === +/** @jsx h */ +import { dom as h } from "./renderer" +>dom : () => void +>h : () => void + +export const prerendered = ; +>prerendered : any +> : any +>h : () => void +>h : () => void + +=== tests/cases/conformance/jsx/inline/othernoalias.tsx === +/** @jsx otherdom */ +import { otherdom } from "./renderer" +>otherdom : () => void + +export const prerendered2 = ; +>prerendered2 : any +> : any +>h : any +>h : any + +=== tests/cases/conformance/jsx/inline/reacty.tsx === +import React from "./renderer" +>React : () => void + +export const prerendered3 = ; +>prerendered3 : any +> : any +>h : any +>h : any + +=== tests/cases/conformance/jsx/inline/index.tsx === +/** @jsx dom */ +import { dom } from "./renderer" +>dom : () => void + + +> : any +>h : any +>h : any + +export * from "./other"; +export * from "./othernoalias"; +export * from "./reacty"; + diff --git a/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.errors.txt b/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.errors.txt new file mode 100644 index 00000000000..438d492d020 --- /dev/null +++ b/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.errors.txt @@ -0,0 +1,129 @@ +tests/cases/conformance/jsx/inline/index.tsx(5,1): error TS2322: Type 'dom.JSX.Element' is not assignable to type 'predom.JSX.Element'. + Property '__predomBrand' is missing in type 'Element'. +tests/cases/conformance/jsx/inline/index.tsx(21,21): error TS2605: JSX element type 'Element' is not a constructor function for JSX elements. + Property 'render' is missing in type 'Element'. +tests/cases/conformance/jsx/inline/index.tsx(21,28): error TS2322: Type '{ children: Element[]; x: number; y: number; }' is not assignable to type '{ children?: Element[]; }'. + Types of property 'children' are incompatible. + Type 'dom.JSX.Element[]' is not assignable to type 'predom.JSX.Element[]'. + Type 'dom.JSX.Element' is not assignable to type 'predom.JSX.Element'. +tests/cases/conformance/jsx/inline/index.tsx(21,40): error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements. +tests/cases/conformance/jsx/inline/index.tsx(21,40): error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements. + Property '__domBrand' is missing in type 'MyClass'. +tests/cases/conformance/jsx/inline/index.tsx(21,63): error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements. +tests/cases/conformance/jsx/inline/index.tsx(24,30): error TS2322: Type '{ children: Element[]; x: number; y: number; }' is not assignable to type '{ x: number; y: number; children?: Element[]; }'. + Types of property 'children' are incompatible. + Type 'predom.JSX.Element[]' is not assignable to type 'dom.JSX.Element[]'. + Type 'predom.JSX.Element' is not assignable to type 'dom.JSX.Element'. + Property '__domBrand' is missing in type 'Element'. + + +==== tests/cases/conformance/jsx/inline/renderer.d.ts (0 errors) ==== + export namespace dom { + namespace JSX { + interface IntrinsicElements { + [e: string]: {}; + } + interface Element { + __domBrand: void; + props: { + children?: Element[]; + }; + } + interface ElementClass extends Element { + render(): Element; + } + interface ElementAttributesProperty { props: any; } + interface ElementChildrenAttribute { children: any; } + } + } + export function dom(): dom.JSX.Element; +==== tests/cases/conformance/jsx/inline/renderer2.d.ts (0 errors) ==== + export namespace predom { + namespace JSX { + interface IntrinsicElements { + [e: string]: {}; + } + interface Element { + __predomBrand: void; + props: { + children?: Element[]; + }; + } + interface ElementClass extends Element { + render(): Element; + } + interface ElementAttributesProperty { props: any; } + interface ElementChildrenAttribute { children: any; } + } + } + export function predom(): predom.JSX.Element; +==== tests/cases/conformance/jsx/inline/component.tsx (0 errors) ==== + /** @jsx predom */ + import { predom } from "./renderer2" + + export const MySFC = (props: {x: number, y: number, children?: predom.JSX.Element[]}) =>

{props.x} + {props.y} = {props.x + props.y}{...this.props.children}

; + + export class MyClass implements predom.JSX.Element { + __predomBrand!: void; + constructor(public props: {x: number, y: number, children?: predom.JSX.Element[]}) {} + render() { + return

+ {this.props.x} + {this.props.y} = {this.props.x + this.props.y} + {...this.props.children} +

; + } + } + export const tree = + + export default + +==== tests/cases/conformance/jsx/inline/index.tsx (7 errors) ==== + /** @jsx dom */ + import { dom } from "./renderer" + import prerendered, {MySFC, MyClass, tree} from "./component"; + let elem = prerendered; + elem = ; // Expect assignability error here + ~~~~ +!!! error TS2322: Type 'dom.JSX.Element' is not assignable to type 'predom.JSX.Element'. +!!! error TS2322: Property '__predomBrand' is missing in type 'Element'. + + const DOMSFC = (props: {x: number, y: number, children?: dom.JSX.Element[]}) =>

{props.x} + {props.y} = {props.x + props.y}{props.children}

; + + class DOMClass implements dom.JSX.Element { + __domBrand!: void; + constructor(public props: {x: number, y: number, children?: dom.JSX.Element[]}) {} + render() { + return

{this.props.x} + {this.props.y} = {this.props.x + this.props.y}{...this.props.children}

; + } + } + + // Should work, everything is a DOM element + const _tree = + + // Should fail, no dom elements + const _brokenTree = + ~~~~~~~~~~~~~~~~~~~ +!!! error TS2605: JSX element type 'Element' is not a constructor function for JSX elements. +!!! error TS2605: Property 'render' is missing in type 'Element'. + ~~~~~~~~~~~ +!!! error TS2322: Type '{ children: Element[]; x: number; y: number; }' is not assignable to type '{ children?: Element[]; }'. +!!! error TS2322: Types of property 'children' are incompatible. +!!! error TS2322: Type 'dom.JSX.Element[]' is not assignable to type 'predom.JSX.Element[]'. +!!! error TS2322: Type 'dom.JSX.Element' is not assignable to type 'predom.JSX.Element'. + ~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements. + ~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements. +!!! error TS2605: Property '__domBrand' is missing in type 'MyClass'. + ~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2605: JSX element type 'MyClass' is not a constructor function for JSX elements. + + // Should fail, nondom isn't allowed as children of dom + const _brokenTree2 = {tree}{tree} + ~~~~~~~~~~~ +!!! error TS2322: Type '{ children: Element[]; x: number; y: number; }' is not assignable to type '{ x: number; y: number; children?: Element[]; }'. +!!! error TS2322: Types of property 'children' are incompatible. +!!! error TS2322: Type 'predom.JSX.Element[]' is not assignable to type 'dom.JSX.Element[]'. +!!! error TS2322: Type 'predom.JSX.Element' is not assignable to type 'dom.JSX.Element'. +!!! error TS2322: Property '__domBrand' is missing in type 'Element'. + \ No newline at end of file diff --git a/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.js b/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.js new file mode 100644 index 00000000000..87487b4139d --- /dev/null +++ b/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.js @@ -0,0 +1,164 @@ +//// [tests/cases/conformance/jsx/inline/inlineJsxFactoryDeclarationsLocalTypes.tsx] //// + +//// [renderer.d.ts] +export namespace dom { + namespace JSX { + interface IntrinsicElements { + [e: string]: {}; + } + interface Element { + __domBrand: void; + props: { + children?: Element[]; + }; + } + interface ElementClass extends Element { + render(): Element; + } + interface ElementAttributesProperty { props: any; } + interface ElementChildrenAttribute { children: any; } + } +} +export function dom(): dom.JSX.Element; +//// [renderer2.d.ts] +export namespace predom { + namespace JSX { + interface IntrinsicElements { + [e: string]: {}; + } + interface Element { + __predomBrand: void; + props: { + children?: Element[]; + }; + } + interface ElementClass extends Element { + render(): Element; + } + interface ElementAttributesProperty { props: any; } + interface ElementChildrenAttribute { children: any; } + } +} +export function predom(): predom.JSX.Element; +//// [component.tsx] +/** @jsx predom */ +import { predom } from "./renderer2" + +export const MySFC = (props: {x: number, y: number, children?: predom.JSX.Element[]}) =>

{props.x} + {props.y} = {props.x + props.y}{...this.props.children}

; + +export class MyClass implements predom.JSX.Element { + __predomBrand!: void; + constructor(public props: {x: number, y: number, children?: predom.JSX.Element[]}) {} + render() { + return

+ {this.props.x} + {this.props.y} = {this.props.x + this.props.y} + {...this.props.children} +

; + } +} +export const tree = + +export default + +//// [index.tsx] +/** @jsx dom */ +import { dom } from "./renderer" +import prerendered, {MySFC, MyClass, tree} from "./component"; +let elem = prerendered; +elem = ; // Expect assignability error here + +const DOMSFC = (props: {x: number, y: number, children?: dom.JSX.Element[]}) =>

{props.x} + {props.y} = {props.x + props.y}{props.children}

; + +class DOMClass implements dom.JSX.Element { + __domBrand!: void; + constructor(public props: {x: number, y: number, children?: dom.JSX.Element[]}) {} + render() { + return

{this.props.x} + {this.props.y} = {this.props.x + this.props.y}{...this.props.children}

; + } +} + +// Should work, everything is a DOM element +const _tree = + +// Should fail, no dom elements +const _brokenTree = + +// Should fail, nondom isn't allowed as children of dom +const _brokenTree2 = {tree}{tree} + + +//// [component.js] +"use strict"; +var _this = this; +exports.__esModule = true; +/** @jsx predom */ +var renderer2_1 = require("./renderer2"); +exports.MySFC = function (props) { return renderer2_1.predom("p", null, + props.x, + " + ", + props.y, + " = ", + props.x + props.y, + _this.props.children); }; +var MyClass = /** @class */ (function () { + function MyClass(props) { + this.props = props; + } + MyClass.prototype.render = function () { + return renderer2_1.predom("p", null, + this.props.x, + " + ", + this.props.y, + " = ", + this.props.x + this.props.y, + this.props.children); + }; + return MyClass; +}()); +exports.MyClass = MyClass; +exports.tree = renderer2_1.predom(exports.MySFC, { x: 1, y: 2 }, + renderer2_1.predom(MyClass, { x: 3, y: 4 }), + renderer2_1.predom(MyClass, { x: 5, y: 6 })); +exports["default"] = renderer2_1.predom("h", null); +//// [index.js] +"use strict"; +exports.__esModule = true; +/** @jsx dom */ +var renderer_1 = require("./renderer"); +var component_1 = require("./component"); +var elem = component_1["default"]; +elem = renderer_1.dom("h", null); // Expect assignability error here +var DOMSFC = function (props) { return renderer_1.dom("p", null, + props.x, + " + ", + props.y, + " = ", + props.x + props.y, + props.children); }; +var DOMClass = /** @class */ (function () { + function DOMClass(props) { + this.props = props; + } + DOMClass.prototype.render = function () { + return renderer_1.dom("p", null, + this.props.x, + " + ", + this.props.y, + " = ", + this.props.x + this.props.y, + this.props.children); + }; + return DOMClass; +}()); +// Should work, everything is a DOM element +var _tree = renderer_1.dom(DOMSFC, { x: 1, y: 2 }, + renderer_1.dom(DOMClass, { x: 3, y: 4 }), + renderer_1.dom(DOMClass, { x: 5, y: 6 })); +// Should fail, no dom elements +var _brokenTree = renderer_1.dom(component_1.MySFC, { x: 1, y: 2 }, + renderer_1.dom(component_1.MyClass, { x: 3, y: 4 }), + renderer_1.dom(component_1.MyClass, { x: 5, y: 6 })); +// Should fail, nondom isn't allowed as children of dom +var _brokenTree2 = renderer_1.dom(DOMSFC, { x: 1, y: 2 }, + component_1.tree, + component_1.tree); diff --git a/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.symbols b/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.symbols new file mode 100644 index 00000000000..c5b4e795cf6 --- /dev/null +++ b/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.symbols @@ -0,0 +1,346 @@ +=== tests/cases/conformance/jsx/inline/renderer.d.ts === +export namespace dom { +>dom : Symbol(dom, Decl(renderer.d.ts, 0, 0), Decl(renderer.d.ts, 17, 1)) + + namespace JSX { +>JSX : Symbol(JSX, Decl(renderer.d.ts, 0, 22)) + + interface IntrinsicElements { +>IntrinsicElements : Symbol(IntrinsicElements, Decl(renderer.d.ts, 1, 19)) + + [e: string]: {}; +>e : Symbol(e, Decl(renderer.d.ts, 3, 13)) + } + interface Element { +>Element : Symbol(Element, Decl(renderer.d.ts, 4, 9)) + + __domBrand: void; +>__domBrand : Symbol(Element.__domBrand, Decl(renderer.d.ts, 5, 27)) + + props: { +>props : Symbol(Element.props, Decl(renderer.d.ts, 6, 29)) + + children?: Element[]; +>children : Symbol(children, Decl(renderer.d.ts, 7, 20)) +>Element : Symbol(Element, Decl(renderer.d.ts, 4, 9)) + + }; + } + interface ElementClass extends Element { +>ElementClass : Symbol(ElementClass, Decl(renderer.d.ts, 10, 9)) +>Element : Symbol(Element, Decl(renderer.d.ts, 4, 9)) + + render(): Element; +>render : Symbol(ElementClass.render, Decl(renderer.d.ts, 11, 48)) +>Element : Symbol(Element, Decl(renderer.d.ts, 4, 9)) + } + interface ElementAttributesProperty { props: any; } +>ElementAttributesProperty : Symbol(ElementAttributesProperty, Decl(renderer.d.ts, 13, 9)) +>props : Symbol(ElementAttributesProperty.props, Decl(renderer.d.ts, 14, 45)) + + interface ElementChildrenAttribute { children: any; } +>ElementChildrenAttribute : Symbol(ElementChildrenAttribute, Decl(renderer.d.ts, 14, 59)) +>children : Symbol(ElementChildrenAttribute.children, Decl(renderer.d.ts, 15, 44)) + } +} +export function dom(): dom.JSX.Element; +>dom : Symbol(dom, Decl(renderer.d.ts, 0, 0), Decl(renderer.d.ts, 17, 1)) +>dom : Symbol(dom, Decl(renderer.d.ts, 0, 0), Decl(renderer.d.ts, 17, 1)) +>JSX : Symbol(dom.JSX, Decl(renderer.d.ts, 0, 22)) +>Element : Symbol(dom.JSX.Element, Decl(renderer.d.ts, 4, 9)) + +=== tests/cases/conformance/jsx/inline/renderer2.d.ts === +export namespace predom { +>predom : Symbol(predom, Decl(renderer2.d.ts, 0, 0), Decl(renderer2.d.ts, 17, 1)) + + namespace JSX { +>JSX : Symbol(JSX, Decl(renderer2.d.ts, 0, 25)) + + interface IntrinsicElements { +>IntrinsicElements : Symbol(IntrinsicElements, Decl(renderer2.d.ts, 1, 19)) + + [e: string]: {}; +>e : Symbol(e, Decl(renderer2.d.ts, 3, 13)) + } + interface Element { +>Element : Symbol(Element, Decl(renderer2.d.ts, 4, 9)) + + __predomBrand: void; +>__predomBrand : Symbol(Element.__predomBrand, Decl(renderer2.d.ts, 5, 27)) + + props: { +>props : Symbol(Element.props, Decl(renderer2.d.ts, 6, 32)) + + children?: Element[]; +>children : Symbol(children, Decl(renderer2.d.ts, 7, 20)) +>Element : Symbol(Element, Decl(renderer2.d.ts, 4, 9)) + + }; + } + interface ElementClass extends Element { +>ElementClass : Symbol(ElementClass, Decl(renderer2.d.ts, 10, 9)) +>Element : Symbol(Element, Decl(renderer2.d.ts, 4, 9)) + + render(): Element; +>render : Symbol(ElementClass.render, Decl(renderer2.d.ts, 11, 48)) +>Element : Symbol(Element, Decl(renderer2.d.ts, 4, 9)) + } + interface ElementAttributesProperty { props: any; } +>ElementAttributesProperty : Symbol(ElementAttributesProperty, Decl(renderer2.d.ts, 13, 9)) +>props : Symbol(ElementAttributesProperty.props, Decl(renderer2.d.ts, 14, 45)) + + interface ElementChildrenAttribute { children: any; } +>ElementChildrenAttribute : Symbol(ElementChildrenAttribute, Decl(renderer2.d.ts, 14, 59)) +>children : Symbol(ElementChildrenAttribute.children, Decl(renderer2.d.ts, 15, 44)) + } +} +export function predom(): predom.JSX.Element; +>predom : Symbol(predom, Decl(renderer2.d.ts, 0, 0), Decl(renderer2.d.ts, 17, 1)) +>predom : Symbol(predom, Decl(renderer2.d.ts, 0, 0), Decl(renderer2.d.ts, 17, 1)) +>JSX : Symbol(predom.JSX, Decl(renderer2.d.ts, 0, 25)) +>Element : Symbol(predom.JSX.Element, Decl(renderer2.d.ts, 4, 9)) + +=== tests/cases/conformance/jsx/inline/component.tsx === +/** @jsx predom */ +import { predom } from "./renderer2" +>predom : Symbol(predom, Decl(component.tsx, 1, 8)) + +export const MySFC = (props: {x: number, y: number, children?: predom.JSX.Element[]}) =>

{props.x} + {props.y} = {props.x + props.y}{...this.props.children}

; +>MySFC : Symbol(MySFC, Decl(component.tsx, 3, 12)) +>props : Symbol(props, Decl(component.tsx, 3, 22)) +>x : Symbol(x, Decl(component.tsx, 3, 30)) +>y : Symbol(y, Decl(component.tsx, 3, 40)) +>children : Symbol(children, Decl(component.tsx, 3, 51)) +>predom : Symbol(predom, Decl(component.tsx, 1, 8)) +>JSX : Symbol(predom.JSX, Decl(renderer2.d.ts, 0, 25)) +>Element : Symbol(predom.JSX.Element, Decl(renderer2.d.ts, 4, 9)) +>p : Symbol(predom.JSX.IntrinsicElements, Decl(renderer2.d.ts, 1, 19)) +>props.x : Symbol(x, Decl(component.tsx, 3, 30)) +>props : Symbol(props, Decl(component.tsx, 3, 22)) +>x : Symbol(x, Decl(component.tsx, 3, 30)) +>props.y : Symbol(y, Decl(component.tsx, 3, 40)) +>props : Symbol(props, Decl(component.tsx, 3, 22)) +>y : Symbol(y, Decl(component.tsx, 3, 40)) +>props.x : Symbol(x, Decl(component.tsx, 3, 30)) +>props : Symbol(props, Decl(component.tsx, 3, 22)) +>x : Symbol(x, Decl(component.tsx, 3, 30)) +>props.y : Symbol(y, Decl(component.tsx, 3, 40)) +>props : Symbol(props, Decl(component.tsx, 3, 22)) +>y : Symbol(y, Decl(component.tsx, 3, 40)) +>p : Symbol(predom.JSX.IntrinsicElements, Decl(renderer2.d.ts, 1, 19)) + +export class MyClass implements predom.JSX.Element { +>MyClass : Symbol(MyClass, Decl(component.tsx, 3, 164)) +>predom.JSX.Element : Symbol(predom.JSX.Element, Decl(renderer2.d.ts, 4, 9)) +>predom.JSX : Symbol(predom.JSX, Decl(renderer2.d.ts, 0, 25)) +>predom : Symbol(predom, Decl(component.tsx, 1, 8)) +>JSX : Symbol(predom.JSX, Decl(renderer2.d.ts, 0, 25)) +>Element : Symbol(predom.JSX.Element, Decl(renderer2.d.ts, 4, 9)) + + __predomBrand!: void; +>__predomBrand : Symbol(MyClass.__predomBrand, Decl(component.tsx, 5, 52)) + + constructor(public props: {x: number, y: number, children?: predom.JSX.Element[]}) {} +>props : Symbol(MyClass.props, Decl(component.tsx, 7, 16)) +>x : Symbol(x, Decl(component.tsx, 7, 31)) +>y : Symbol(y, Decl(component.tsx, 7, 41)) +>children : Symbol(children, Decl(component.tsx, 7, 52)) +>predom : Symbol(predom, Decl(component.tsx, 1, 8)) +>JSX : Symbol(predom.JSX, Decl(renderer2.d.ts, 0, 25)) +>Element : Symbol(predom.JSX.Element, Decl(renderer2.d.ts, 4, 9)) + + render() { +>render : Symbol(MyClass.render, Decl(component.tsx, 7, 89)) + + return

+>p : Symbol(predom.JSX.IntrinsicElements, Decl(renderer2.d.ts, 1, 19)) + + {this.props.x} + {this.props.y} = {this.props.x + this.props.y} +>this.props.x : Symbol(x, Decl(component.tsx, 7, 31)) +>this.props : Symbol(MyClass.props, Decl(component.tsx, 7, 16)) +>this : Symbol(MyClass, Decl(component.tsx, 3, 164)) +>props : Symbol(MyClass.props, Decl(component.tsx, 7, 16)) +>x : Symbol(x, Decl(component.tsx, 7, 31)) +>this.props.y : Symbol(y, Decl(component.tsx, 7, 41)) +>this.props : Symbol(MyClass.props, Decl(component.tsx, 7, 16)) +>this : Symbol(MyClass, Decl(component.tsx, 3, 164)) +>props : Symbol(MyClass.props, Decl(component.tsx, 7, 16)) +>y : Symbol(y, Decl(component.tsx, 7, 41)) +>this.props.x : Symbol(x, Decl(component.tsx, 7, 31)) +>this.props : Symbol(MyClass.props, Decl(component.tsx, 7, 16)) +>this : Symbol(MyClass, Decl(component.tsx, 3, 164)) +>props : Symbol(MyClass.props, Decl(component.tsx, 7, 16)) +>x : Symbol(x, Decl(component.tsx, 7, 31)) +>this.props.y : Symbol(y, Decl(component.tsx, 7, 41)) +>this.props : Symbol(MyClass.props, Decl(component.tsx, 7, 16)) +>this : Symbol(MyClass, Decl(component.tsx, 3, 164)) +>props : Symbol(MyClass.props, Decl(component.tsx, 7, 16)) +>y : Symbol(y, Decl(component.tsx, 7, 41)) + + {...this.props.children} +>this.props.children : Symbol(children, Decl(component.tsx, 7, 52)) +>this.props : Symbol(MyClass.props, Decl(component.tsx, 7, 16)) +>this : Symbol(MyClass, Decl(component.tsx, 3, 164)) +>props : Symbol(MyClass.props, Decl(component.tsx, 7, 16)) +>children : Symbol(children, Decl(component.tsx, 7, 52)) + +

; +>p : Symbol(predom.JSX.IntrinsicElements, Decl(renderer2.d.ts, 1, 19)) + } +} +export const tree = +>tree : Symbol(tree, Decl(component.tsx, 15, 12)) +>MySFC : Symbol(MySFC, Decl(component.tsx, 3, 12)) +>x : Symbol(x, Decl(component.tsx, 15, 26)) +>y : Symbol(y, Decl(component.tsx, 15, 32)) +>MyClass : Symbol(MyClass, Decl(component.tsx, 3, 164)) +>x : Symbol(x, Decl(component.tsx, 15, 47)) +>y : Symbol(y, Decl(component.tsx, 15, 53)) +>MyClass : Symbol(MyClass, Decl(component.tsx, 3, 164)) +>x : Symbol(x, Decl(component.tsx, 15, 70)) +>y : Symbol(y, Decl(component.tsx, 15, 76)) +>MySFC : Symbol(MySFC, Decl(component.tsx, 3, 12)) + +export default +>h : Symbol(predom.JSX.IntrinsicElements, Decl(renderer2.d.ts, 1, 19)) +>h : Symbol(predom.JSX.IntrinsicElements, Decl(renderer2.d.ts, 1, 19)) + +=== tests/cases/conformance/jsx/inline/index.tsx === +/** @jsx dom */ +import { dom } from "./renderer" +>dom : Symbol(dom, Decl(index.tsx, 1, 8)) + +import prerendered, {MySFC, MyClass, tree} from "./component"; +>prerendered : Symbol(prerendered, Decl(index.tsx, 2, 6)) +>MySFC : Symbol(MySFC, Decl(index.tsx, 2, 21)) +>MyClass : Symbol(MyClass, Decl(index.tsx, 2, 27)) +>tree : Symbol(tree, Decl(index.tsx, 2, 36)) + +let elem = prerendered; +>elem : Symbol(elem, Decl(index.tsx, 3, 3)) +>prerendered : Symbol(prerendered, Decl(index.tsx, 2, 6)) + +elem = ; // Expect assignability error here +>elem : Symbol(elem, Decl(index.tsx, 3, 3)) +>h : Symbol(dom.JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) +>h : Symbol(dom.JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) + +const DOMSFC = (props: {x: number, y: number, children?: dom.JSX.Element[]}) =>

{props.x} + {props.y} = {props.x + props.y}{props.children}

; +>DOMSFC : Symbol(DOMSFC, Decl(index.tsx, 6, 5)) +>props : Symbol(props, Decl(index.tsx, 6, 16)) +>x : Symbol(x, Decl(index.tsx, 6, 24)) +>y : Symbol(y, Decl(index.tsx, 6, 34)) +>children : Symbol(children, Decl(index.tsx, 6, 45)) +>dom : Symbol(dom, Decl(index.tsx, 1, 8)) +>JSX : Symbol(dom.JSX, Decl(renderer.d.ts, 0, 22)) +>Element : Symbol(dom.JSX.Element, Decl(renderer.d.ts, 4, 9)) +>p : Symbol(dom.JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) +>props.x : Symbol(x, Decl(index.tsx, 6, 24)) +>props : Symbol(props, Decl(index.tsx, 6, 16)) +>x : Symbol(x, Decl(index.tsx, 6, 24)) +>props.y : Symbol(y, Decl(index.tsx, 6, 34)) +>props : Symbol(props, Decl(index.tsx, 6, 16)) +>y : Symbol(y, Decl(index.tsx, 6, 34)) +>props.x : Symbol(x, Decl(index.tsx, 6, 24)) +>props : Symbol(props, Decl(index.tsx, 6, 16)) +>x : Symbol(x, Decl(index.tsx, 6, 24)) +>props.y : Symbol(y, Decl(index.tsx, 6, 34)) +>props : Symbol(props, Decl(index.tsx, 6, 16)) +>y : Symbol(y, Decl(index.tsx, 6, 34)) +>props.children : Symbol(children, Decl(index.tsx, 6, 45)) +>props : Symbol(props, Decl(index.tsx, 6, 16)) +>children : Symbol(children, Decl(index.tsx, 6, 45)) +>p : Symbol(dom.JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) + +class DOMClass implements dom.JSX.Element { +>DOMClass : Symbol(DOMClass, Decl(index.tsx, 6, 147)) +>dom.JSX.Element : Symbol(dom.JSX.Element, Decl(renderer.d.ts, 4, 9)) +>dom.JSX : Symbol(dom.JSX, Decl(renderer.d.ts, 0, 22)) +>dom : Symbol(dom, Decl(index.tsx, 1, 8)) +>JSX : Symbol(dom.JSX, Decl(renderer.d.ts, 0, 22)) +>Element : Symbol(dom.JSX.Element, Decl(renderer.d.ts, 4, 9)) + + __domBrand!: void; +>__domBrand : Symbol(DOMClass.__domBrand, Decl(index.tsx, 8, 43)) + + constructor(public props: {x: number, y: number, children?: dom.JSX.Element[]}) {} +>props : Symbol(DOMClass.props, Decl(index.tsx, 10, 16)) +>x : Symbol(x, Decl(index.tsx, 10, 31)) +>y : Symbol(y, Decl(index.tsx, 10, 41)) +>children : Symbol(children, Decl(index.tsx, 10, 52)) +>dom : Symbol(dom, Decl(index.tsx, 1, 8)) +>JSX : Symbol(dom.JSX, Decl(renderer.d.ts, 0, 22)) +>Element : Symbol(dom.JSX.Element, Decl(renderer.d.ts, 4, 9)) + + render() { +>render : Symbol(DOMClass.render, Decl(index.tsx, 10, 86)) + + return

{this.props.x} + {this.props.y} = {this.props.x + this.props.y}{...this.props.children}

; +>p : Symbol(dom.JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) +>this.props.x : Symbol(x, Decl(index.tsx, 10, 31)) +>this.props : Symbol(DOMClass.props, Decl(index.tsx, 10, 16)) +>this : Symbol(DOMClass, Decl(index.tsx, 6, 147)) +>props : Symbol(DOMClass.props, Decl(index.tsx, 10, 16)) +>x : Symbol(x, Decl(index.tsx, 10, 31)) +>this.props.y : Symbol(y, Decl(index.tsx, 10, 41)) +>this.props : Symbol(DOMClass.props, Decl(index.tsx, 10, 16)) +>this : Symbol(DOMClass, Decl(index.tsx, 6, 147)) +>props : Symbol(DOMClass.props, Decl(index.tsx, 10, 16)) +>y : Symbol(y, Decl(index.tsx, 10, 41)) +>this.props.x : Symbol(x, Decl(index.tsx, 10, 31)) +>this.props : Symbol(DOMClass.props, Decl(index.tsx, 10, 16)) +>this : Symbol(DOMClass, Decl(index.tsx, 6, 147)) +>props : Symbol(DOMClass.props, Decl(index.tsx, 10, 16)) +>x : Symbol(x, Decl(index.tsx, 10, 31)) +>this.props.y : Symbol(y, Decl(index.tsx, 10, 41)) +>this.props : Symbol(DOMClass.props, Decl(index.tsx, 10, 16)) +>this : Symbol(DOMClass, Decl(index.tsx, 6, 147)) +>props : Symbol(DOMClass.props, Decl(index.tsx, 10, 16)) +>y : Symbol(y, Decl(index.tsx, 10, 41)) +>this.props.children : Symbol(children, Decl(index.tsx, 10, 52)) +>this.props : Symbol(DOMClass.props, Decl(index.tsx, 10, 16)) +>this : Symbol(DOMClass, Decl(index.tsx, 6, 147)) +>props : Symbol(DOMClass.props, Decl(index.tsx, 10, 16)) +>children : Symbol(children, Decl(index.tsx, 10, 52)) +>p : Symbol(dom.JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) + } +} + +// Should work, everything is a DOM element +const _tree = +>_tree : Symbol(_tree, Decl(index.tsx, 17, 5)) +>DOMSFC : Symbol(DOMSFC, Decl(index.tsx, 6, 5)) +>x : Symbol(x, Decl(index.tsx, 17, 21)) +>y : Symbol(y, Decl(index.tsx, 17, 27)) +>DOMClass : Symbol(DOMClass, Decl(index.tsx, 6, 147)) +>x : Symbol(x, Decl(index.tsx, 17, 43)) +>y : Symbol(y, Decl(index.tsx, 17, 49)) +>DOMClass : Symbol(DOMClass, Decl(index.tsx, 6, 147)) +>x : Symbol(x, Decl(index.tsx, 17, 67)) +>y : Symbol(y, Decl(index.tsx, 17, 73)) +>DOMSFC : Symbol(DOMSFC, Decl(index.tsx, 6, 5)) + +// Should fail, no dom elements +const _brokenTree = +>_brokenTree : Symbol(_brokenTree, Decl(index.tsx, 20, 5)) +>MySFC : Symbol(MySFC, Decl(index.tsx, 2, 21)) +>x : Symbol(x, Decl(index.tsx, 20, 26)) +>y : Symbol(y, Decl(index.tsx, 20, 32)) +>MyClass : Symbol(MyClass, Decl(index.tsx, 2, 27)) +>x : Symbol(x, Decl(index.tsx, 20, 47)) +>y : Symbol(y, Decl(index.tsx, 20, 53)) +>MyClass : Symbol(MyClass, Decl(index.tsx, 2, 27)) +>x : Symbol(x, Decl(index.tsx, 20, 70)) +>y : Symbol(y, Decl(index.tsx, 20, 76)) +>MySFC : Symbol(MySFC, Decl(index.tsx, 2, 21)) + +// Should fail, nondom isn't allowed as children of dom +const _brokenTree2 = {tree}{tree} +>_brokenTree2 : Symbol(_brokenTree2, Decl(index.tsx, 23, 5)) +>DOMSFC : Symbol(DOMSFC, Decl(index.tsx, 6, 5)) +>x : Symbol(x, Decl(index.tsx, 23, 28)) +>y : Symbol(y, Decl(index.tsx, 23, 34)) +>tree : Symbol(tree, Decl(index.tsx, 2, 36)) +>tree : Symbol(tree, Decl(index.tsx, 2, 36)) +>DOMSFC : Symbol(DOMSFC, Decl(index.tsx, 6, 5)) + diff --git a/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.types b/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.types new file mode 100644 index 00000000000..d33da0d6494 --- /dev/null +++ b/tests/baselines/reference/inlineJsxFactoryDeclarationsLocalTypes.types @@ -0,0 +1,394 @@ +=== tests/cases/conformance/jsx/inline/renderer.d.ts === +export namespace dom { +>dom : () => JSX.Element + + namespace JSX { +>JSX : any + + interface IntrinsicElements { +>IntrinsicElements : IntrinsicElements + + [e: string]: {}; +>e : string + } + interface Element { +>Element : Element + + __domBrand: void; +>__domBrand : void + + props: { +>props : { children?: Element[]; } + + children?: Element[]; +>children : Element[] +>Element : Element + + }; + } + interface ElementClass extends Element { +>ElementClass : ElementClass +>Element : Element + + render(): Element; +>render : () => Element +>Element : Element + } + interface ElementAttributesProperty { props: any; } +>ElementAttributesProperty : ElementAttributesProperty +>props : any + + interface ElementChildrenAttribute { children: any; } +>ElementChildrenAttribute : ElementChildrenAttribute +>children : any + } +} +export function dom(): dom.JSX.Element; +>dom : () => dom.JSX.Element +>dom : any +>JSX : any +>Element : dom.JSX.Element + +=== tests/cases/conformance/jsx/inline/renderer2.d.ts === +export namespace predom { +>predom : () => JSX.Element + + namespace JSX { +>JSX : any + + interface IntrinsicElements { +>IntrinsicElements : IntrinsicElements + + [e: string]: {}; +>e : string + } + interface Element { +>Element : Element + + __predomBrand: void; +>__predomBrand : void + + props: { +>props : { children?: Element[]; } + + children?: Element[]; +>children : Element[] +>Element : Element + + }; + } + interface ElementClass extends Element { +>ElementClass : ElementClass +>Element : Element + + render(): Element; +>render : () => Element +>Element : Element + } + interface ElementAttributesProperty { props: any; } +>ElementAttributesProperty : ElementAttributesProperty +>props : any + + interface ElementChildrenAttribute { children: any; } +>ElementChildrenAttribute : ElementChildrenAttribute +>children : any + } +} +export function predom(): predom.JSX.Element; +>predom : () => predom.JSX.Element +>predom : any +>JSX : any +>Element : predom.JSX.Element + +=== tests/cases/conformance/jsx/inline/component.tsx === +/** @jsx predom */ +import { predom } from "./renderer2" +>predom : () => predom.JSX.Element + +export const MySFC = (props: {x: number, y: number, children?: predom.JSX.Element[]}) =>

{props.x} + {props.y} = {props.x + props.y}{...this.props.children}

; +>MySFC : (props: { x: number; y: number; children?: predom.JSX.Element[]; }) => predom.JSX.Element +>(props: {x: number, y: number, children?: predom.JSX.Element[]}) =>

{props.x} + {props.y} = {props.x + props.y}{...this.props.children}

: (props: { x: number; y: number; children?: predom.JSX.Element[]; }) => predom.JSX.Element +>props : { x: number; y: number; children?: predom.JSX.Element[]; } +>x : number +>y : number +>children : predom.JSX.Element[] +>predom : any +>JSX : any +>Element : predom.JSX.Element +>

{props.x} + {props.y} = {props.x + props.y}{...this.props.children}

: predom.JSX.Element +>p : any +>props.x : number +>props : { x: number; y: number; children?: predom.JSX.Element[]; } +>x : number +>props.y : number +>props : { x: number; y: number; children?: predom.JSX.Element[]; } +>y : number +>props.x + props.y : number +>props.x : number +>props : { x: number; y: number; children?: predom.JSX.Element[]; } +>x : number +>props.y : number +>props : { x: number; y: number; children?: predom.JSX.Element[]; } +>y : number +>this.props.children : any +>this.props : any +>this : any +>props : any +>children : any +>p : any + +export class MyClass implements predom.JSX.Element { +>MyClass : MyClass +>predom.JSX.Element : any +>predom.JSX : any +>predom : () => predom.JSX.Element +>JSX : any +>Element : predom.JSX.Element + + __predomBrand!: void; +>__predomBrand : void + + constructor(public props: {x: number, y: number, children?: predom.JSX.Element[]}) {} +>props : { x: number; y: number; children?: predom.JSX.Element[]; } +>x : number +>y : number +>children : predom.JSX.Element[] +>predom : any +>JSX : any +>Element : predom.JSX.Element + + render() { +>render : () => predom.JSX.Element + + return

+>

{this.props.x} + {this.props.y} = {this.props.x + this.props.y} {...this.props.children}

: predom.JSX.Element +>p : any + + {this.props.x} + {this.props.y} = {this.props.x + this.props.y} +>this.props.x : number +>this.props : { x: number; y: number; children?: predom.JSX.Element[]; } +>this : this +>props : { x: number; y: number; children?: predom.JSX.Element[]; } +>x : number +>this.props.y : number +>this.props : { x: number; y: number; children?: predom.JSX.Element[]; } +>this : this +>props : { x: number; y: number; children?: predom.JSX.Element[]; } +>y : number +>this.props.x + this.props.y : number +>this.props.x : number +>this.props : { x: number; y: number; children?: predom.JSX.Element[]; } +>this : this +>props : { x: number; y: number; children?: predom.JSX.Element[]; } +>x : number +>this.props.y : number +>this.props : { x: number; y: number; children?: predom.JSX.Element[]; } +>this : this +>props : { x: number; y: number; children?: predom.JSX.Element[]; } +>y : number + + {...this.props.children} +>this.props.children : predom.JSX.Element[] +>this.props : { x: number; y: number; children?: predom.JSX.Element[]; } +>this : this +>props : { x: number; y: number; children?: predom.JSX.Element[]; } +>children : predom.JSX.Element[] + +

; +>p : any + } +} +export const tree = +>tree : predom.JSX.Element +> : predom.JSX.Element +>MySFC : (props: { x: number; y: number; children?: predom.JSX.Element[]; }) => predom.JSX.Element +>x : number +>1 : 1 +>y : number +>2 : 2 +> : predom.JSX.Element +>MyClass : typeof MyClass +>x : number +>3 : 3 +>y : number +>4 : 4 +> : predom.JSX.Element +>MyClass : typeof MyClass +>x : number +>5 : 5 +>y : number +>6 : 6 +>MySFC : (props: { x: number; y: number; children?: predom.JSX.Element[]; }) => predom.JSX.Element + +export default +> : predom.JSX.Element +>h : any +>h : any + +=== tests/cases/conformance/jsx/inline/index.tsx === +/** @jsx dom */ +import { dom } from "./renderer" +>dom : () => dom.JSX.Element + +import prerendered, {MySFC, MyClass, tree} from "./component"; +>prerendered : predom.JSX.Element +>MySFC : (props: { x: number; y: number; children?: predom.JSX.Element[]; }) => predom.JSX.Element +>MyClass : typeof MyClass +>tree : predom.JSX.Element + +let elem = prerendered; +>elem : predom.JSX.Element +>prerendered : predom.JSX.Element + +elem = ; // Expect assignability error here +>elem = : dom.JSX.Element +>elem : predom.JSX.Element +> : dom.JSX.Element +>h : any +>h : any + +const DOMSFC = (props: {x: number, y: number, children?: dom.JSX.Element[]}) =>

{props.x} + {props.y} = {props.x + props.y}{props.children}

; +>DOMSFC : (props: { x: number; y: number; children?: dom.JSX.Element[]; }) => dom.JSX.Element +>(props: {x: number, y: number, children?: dom.JSX.Element[]}) =>

{props.x} + {props.y} = {props.x + props.y}{props.children}

: (props: { x: number; y: number; children?: dom.JSX.Element[]; }) => dom.JSX.Element +>props : { x: number; y: number; children?: dom.JSX.Element[]; } +>x : number +>y : number +>children : dom.JSX.Element[] +>dom : any +>JSX : any +>Element : dom.JSX.Element +>

{props.x} + {props.y} = {props.x + props.y}{props.children}

: dom.JSX.Element +>p : any +>props.x : number +>props : { x: number; y: number; children?: dom.JSX.Element[]; } +>x : number +>props.y : number +>props : { x: number; y: number; children?: dom.JSX.Element[]; } +>y : number +>props.x + props.y : number +>props.x : number +>props : { x: number; y: number; children?: dom.JSX.Element[]; } +>x : number +>props.y : number +>props : { x: number; y: number; children?: dom.JSX.Element[]; } +>y : number +>props.children : dom.JSX.Element[] +>props : { x: number; y: number; children?: dom.JSX.Element[]; } +>children : dom.JSX.Element[] +>p : any + +class DOMClass implements dom.JSX.Element { +>DOMClass : DOMClass +>dom.JSX.Element : any +>dom.JSX : any +>dom : () => dom.JSX.Element +>JSX : any +>Element : dom.JSX.Element + + __domBrand!: void; +>__domBrand : void + + constructor(public props: {x: number, y: number, children?: dom.JSX.Element[]}) {} +>props : { x: number; y: number; children?: dom.JSX.Element[]; } +>x : number +>y : number +>children : dom.JSX.Element[] +>dom : any +>JSX : any +>Element : dom.JSX.Element + + render() { +>render : () => dom.JSX.Element + + return

{this.props.x} + {this.props.y} = {this.props.x + this.props.y}{...this.props.children}

; +>

{this.props.x} + {this.props.y} = {this.props.x + this.props.y}{...this.props.children}

: dom.JSX.Element +>p : any +>this.props.x : number +>this.props : { x: number; y: number; children?: dom.JSX.Element[]; } +>this : this +>props : { x: number; y: number; children?: dom.JSX.Element[]; } +>x : number +>this.props.y : number +>this.props : { x: number; y: number; children?: dom.JSX.Element[]; } +>this : this +>props : { x: number; y: number; children?: dom.JSX.Element[]; } +>y : number +>this.props.x + this.props.y : number +>this.props.x : number +>this.props : { x: number; y: number; children?: dom.JSX.Element[]; } +>this : this +>props : { x: number; y: number; children?: dom.JSX.Element[]; } +>x : number +>this.props.y : number +>this.props : { x: number; y: number; children?: dom.JSX.Element[]; } +>this : this +>props : { x: number; y: number; children?: dom.JSX.Element[]; } +>y : number +>this.props.children : dom.JSX.Element[] +>this.props : { x: number; y: number; children?: dom.JSX.Element[]; } +>this : this +>props : { x: number; y: number; children?: dom.JSX.Element[]; } +>children : dom.JSX.Element[] +>p : any + } +} + +// Should work, everything is a DOM element +const _tree = +>_tree : dom.JSX.Element +> : dom.JSX.Element +>DOMSFC : (props: { x: number; y: number; children?: dom.JSX.Element[]; }) => dom.JSX.Element +>x : number +>1 : 1 +>y : number +>2 : 2 +> : dom.JSX.Element +>DOMClass : typeof DOMClass +>x : number +>3 : 3 +>y : number +>4 : 4 +> : dom.JSX.Element +>DOMClass : typeof DOMClass +>x : number +>5 : 5 +>y : number +>6 : 6 +>DOMSFC : (props: { x: number; y: number; children?: dom.JSX.Element[]; }) => dom.JSX.Element + +// Should fail, no dom elements +const _brokenTree = +>_brokenTree : dom.JSX.Element +> : dom.JSX.Element +>MySFC : (props: { x: number; y: number; children?: predom.JSX.Element[]; }) => predom.JSX.Element +>x : number +>1 : 1 +>y : number +>2 : 2 +> : dom.JSX.Element +>MyClass : typeof MyClass +>x : number +>3 : 3 +>y : number +>4 : 4 +> : dom.JSX.Element +>MyClass : typeof MyClass +>x : number +>5 : 5 +>y : number +>6 : 6 +>MySFC : (props: { x: number; y: number; children?: predom.JSX.Element[]; }) => predom.JSX.Element + +// Should fail, nondom isn't allowed as children of dom +const _brokenTree2 = {tree}{tree} +>_brokenTree2 : dom.JSX.Element +>{tree}{tree} : dom.JSX.Element +>DOMSFC : (props: { x: number; y: number; children?: dom.JSX.Element[]; }) => dom.JSX.Element +>x : number +>1 : 1 +>y : number +>2 : 2 +>tree : predom.JSX.Element +>tree : predom.JSX.Element +>DOMSFC : (props: { x: number; y: number; children?: dom.JSX.Element[]; }) => dom.JSX.Element + diff --git a/tests/baselines/reference/inlineJsxFactoryLocalTypeGlobalFallback.errors.txt b/tests/baselines/reference/inlineJsxFactoryLocalTypeGlobalFallback.errors.txt new file mode 100644 index 00000000000..9d4e4e0a026 --- /dev/null +++ b/tests/baselines/reference/inlineJsxFactoryLocalTypeGlobalFallback.errors.txt @@ -0,0 +1,51 @@ +tests/cases/conformance/jsx/inline/index.tsx(5,1): error TS2322: Type 'JSX.Element' is not assignable to type 'predom.JSX.Element'. + Property '__predomBrand' is missing in type 'Element'. + + +==== tests/cases/conformance/jsx/inline/renderer.d.ts (0 errors) ==== + declare global { + namespace JSX { + interface IntrinsicElements { + [e: string]: {}; + } + interface Element { + __domBrand: void; + children: Element[]; + props: {}; + } + interface ElementAttributesProperty { props: any; } + interface ElementChildrenAttribute { children: any; } + } + } + export function dom(): JSX.Element; +==== tests/cases/conformance/jsx/inline/renderer2.d.ts (0 errors) ==== + export namespace predom { + namespace JSX { + interface IntrinsicElements { + [e: string]: {}; + } + interface Element { + __predomBrand: void; + children: Element[]; + props: {}; + } + interface ElementAttributesProperty { props: any; } + interface ElementChildrenAttribute { children: any; } + } + } + export function predom(): predom.JSX.Element; +==== tests/cases/conformance/jsx/inline/component.tsx (0 errors) ==== + /** @jsx predom */ + import { predom } from "./renderer2" + export default + +==== tests/cases/conformance/jsx/inline/index.tsx (1 errors) ==== + /** @jsx dom */ + import { dom } from "./renderer" + import prerendered from "./component"; + let elem = prerendered; + elem = ; // Expect assignability error here + ~~~~ +!!! error TS2322: Type 'JSX.Element' is not assignable to type 'predom.JSX.Element'. +!!! error TS2322: Property '__predomBrand' is missing in type 'Element'. + \ No newline at end of file diff --git a/tests/baselines/reference/inlineJsxFactoryLocalTypeGlobalFallback.js b/tests/baselines/reference/inlineJsxFactoryLocalTypeGlobalFallback.js new file mode 100644 index 00000000000..4f5123ed67d --- /dev/null +++ b/tests/baselines/reference/inlineJsxFactoryLocalTypeGlobalFallback.js @@ -0,0 +1,61 @@ +//// [tests/cases/conformance/jsx/inline/inlineJsxFactoryLocalTypeGlobalFallback.tsx] //// + +//// [renderer.d.ts] +declare global { + namespace JSX { + interface IntrinsicElements { + [e: string]: {}; + } + interface Element { + __domBrand: void; + children: Element[]; + props: {}; + } + interface ElementAttributesProperty { props: any; } + interface ElementChildrenAttribute { children: any; } + } +} +export function dom(): JSX.Element; +//// [renderer2.d.ts] +export namespace predom { + namespace JSX { + interface IntrinsicElements { + [e: string]: {}; + } + interface Element { + __predomBrand: void; + children: Element[]; + props: {}; + } + interface ElementAttributesProperty { props: any; } + interface ElementChildrenAttribute { children: any; } + } +} +export function predom(): predom.JSX.Element; +//// [component.tsx] +/** @jsx predom */ +import { predom } from "./renderer2" +export default + +//// [index.tsx] +/** @jsx dom */ +import { dom } from "./renderer" +import prerendered from "./component"; +let elem = prerendered; +elem = ; // Expect assignability error here + + +//// [component.js] +"use strict"; +exports.__esModule = true; +/** @jsx predom */ +var renderer2_1 = require("./renderer2"); +exports["default"] = renderer2_1.predom("h", null); +//// [index.js] +"use strict"; +exports.__esModule = true; +/** @jsx dom */ +var renderer_1 = require("./renderer"); +var component_1 = require("./component"); +var elem = component_1["default"]; +elem = renderer_1.dom("h", null); // Expect assignability error here diff --git a/tests/baselines/reference/inlineJsxFactoryLocalTypeGlobalFallback.symbols b/tests/baselines/reference/inlineJsxFactoryLocalTypeGlobalFallback.symbols new file mode 100644 index 00000000000..c4962015871 --- /dev/null +++ b/tests/baselines/reference/inlineJsxFactoryLocalTypeGlobalFallback.symbols @@ -0,0 +1,107 @@ +=== tests/cases/conformance/jsx/inline/renderer.d.ts === +declare global { +>global : Symbol(global, Decl(renderer.d.ts, 0, 0)) + + namespace JSX { +>JSX : Symbol(JSX, Decl(renderer.d.ts, 0, 16)) + + interface IntrinsicElements { +>IntrinsicElements : Symbol(IntrinsicElements, Decl(renderer.d.ts, 1, 19)) + + [e: string]: {}; +>e : Symbol(e, Decl(renderer.d.ts, 3, 13)) + } + interface Element { +>Element : Symbol(Element, Decl(renderer.d.ts, 4, 9)) + + __domBrand: void; +>__domBrand : Symbol(Element.__domBrand, Decl(renderer.d.ts, 5, 27)) + + children: Element[]; +>children : Symbol(Element.children, Decl(renderer.d.ts, 6, 29)) +>Element : Symbol(Element, Decl(renderer.d.ts, 4, 9)) + + props: {}; +>props : Symbol(Element.props, Decl(renderer.d.ts, 7, 32)) + } + interface ElementAttributesProperty { props: any; } +>ElementAttributesProperty : Symbol(ElementAttributesProperty, Decl(renderer.d.ts, 9, 9)) +>props : Symbol(ElementAttributesProperty.props, Decl(renderer.d.ts, 10, 45)) + + interface ElementChildrenAttribute { children: any; } +>ElementChildrenAttribute : Symbol(ElementChildrenAttribute, Decl(renderer.d.ts, 10, 59)) +>children : Symbol(ElementChildrenAttribute.children, Decl(renderer.d.ts, 11, 44)) + } +} +export function dom(): JSX.Element; +>dom : Symbol(dom, Decl(renderer.d.ts, 13, 1)) +>JSX : Symbol(JSX, Decl(renderer.d.ts, 0, 16)) +>Element : Symbol(JSX.Element, Decl(renderer.d.ts, 4, 9)) + +=== tests/cases/conformance/jsx/inline/renderer2.d.ts === +export namespace predom { +>predom : Symbol(predom, Decl(renderer2.d.ts, 0, 0), Decl(renderer2.d.ts, 13, 1)) + + namespace JSX { +>JSX : Symbol(JSX, Decl(renderer2.d.ts, 0, 25)) + + interface IntrinsicElements { +>IntrinsicElements : Symbol(IntrinsicElements, Decl(renderer2.d.ts, 1, 19)) + + [e: string]: {}; +>e : Symbol(e, Decl(renderer2.d.ts, 3, 13)) + } + interface Element { +>Element : Symbol(Element, Decl(renderer2.d.ts, 4, 9)) + + __predomBrand: void; +>__predomBrand : Symbol(Element.__predomBrand, Decl(renderer2.d.ts, 5, 27)) + + children: Element[]; +>children : Symbol(Element.children, Decl(renderer2.d.ts, 6, 32)) +>Element : Symbol(Element, Decl(renderer2.d.ts, 4, 9)) + + props: {}; +>props : Symbol(Element.props, Decl(renderer2.d.ts, 7, 32)) + } + interface ElementAttributesProperty { props: any; } +>ElementAttributesProperty : Symbol(ElementAttributesProperty, Decl(renderer2.d.ts, 9, 9)) +>props : Symbol(ElementAttributesProperty.props, Decl(renderer2.d.ts, 10, 45)) + + interface ElementChildrenAttribute { children: any; } +>ElementChildrenAttribute : Symbol(ElementChildrenAttribute, Decl(renderer2.d.ts, 10, 59)) +>children : Symbol(ElementChildrenAttribute.children, Decl(renderer2.d.ts, 11, 44)) + } +} +export function predom(): predom.JSX.Element; +>predom : Symbol(predom, Decl(renderer2.d.ts, 0, 0), Decl(renderer2.d.ts, 13, 1)) +>predom : Symbol(predom, Decl(renderer2.d.ts, 0, 0), Decl(renderer2.d.ts, 13, 1)) +>JSX : Symbol(predom.JSX, Decl(renderer2.d.ts, 0, 25)) +>Element : Symbol(predom.JSX.Element, Decl(renderer2.d.ts, 4, 9)) + +=== tests/cases/conformance/jsx/inline/component.tsx === +/** @jsx predom */ +import { predom } from "./renderer2" +>predom : Symbol(predom, Decl(component.tsx, 1, 8)) + +export default +>h : Symbol(predom.JSX.IntrinsicElements, Decl(renderer2.d.ts, 1, 19)) +>h : Symbol(predom.JSX.IntrinsicElements, Decl(renderer2.d.ts, 1, 19)) + +=== tests/cases/conformance/jsx/inline/index.tsx === +/** @jsx dom */ +import { dom } from "./renderer" +>dom : Symbol(dom, Decl(index.tsx, 1, 8)) + +import prerendered from "./component"; +>prerendered : Symbol(prerendered, Decl(index.tsx, 2, 6)) + +let elem = prerendered; +>elem : Symbol(elem, Decl(index.tsx, 3, 3)) +>prerendered : Symbol(prerendered, Decl(index.tsx, 2, 6)) + +elem = ; // Expect assignability error here +>elem : Symbol(elem, Decl(index.tsx, 3, 3)) +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) + diff --git a/tests/baselines/reference/inlineJsxFactoryLocalTypeGlobalFallback.types b/tests/baselines/reference/inlineJsxFactoryLocalTypeGlobalFallback.types new file mode 100644 index 00000000000..369341f0f7a --- /dev/null +++ b/tests/baselines/reference/inlineJsxFactoryLocalTypeGlobalFallback.types @@ -0,0 +1,110 @@ +=== tests/cases/conformance/jsx/inline/renderer.d.ts === +declare global { +>global : any + + namespace JSX { +>JSX : any + + interface IntrinsicElements { +>IntrinsicElements : IntrinsicElements + + [e: string]: {}; +>e : string + } + interface Element { +>Element : Element + + __domBrand: void; +>__domBrand : void + + children: Element[]; +>children : Element[] +>Element : Element + + props: {}; +>props : {} + } + interface ElementAttributesProperty { props: any; } +>ElementAttributesProperty : ElementAttributesProperty +>props : any + + interface ElementChildrenAttribute { children: any; } +>ElementChildrenAttribute : ElementChildrenAttribute +>children : any + } +} +export function dom(): JSX.Element; +>dom : () => JSX.Element +>JSX : any +>Element : JSX.Element + +=== tests/cases/conformance/jsx/inline/renderer2.d.ts === +export namespace predom { +>predom : () => JSX.Element + + namespace JSX { +>JSX : any + + interface IntrinsicElements { +>IntrinsicElements : IntrinsicElements + + [e: string]: {}; +>e : string + } + interface Element { +>Element : Element + + __predomBrand: void; +>__predomBrand : void + + children: Element[]; +>children : Element[] +>Element : Element + + props: {}; +>props : {} + } + interface ElementAttributesProperty { props: any; } +>ElementAttributesProperty : ElementAttributesProperty +>props : any + + interface ElementChildrenAttribute { children: any; } +>ElementChildrenAttribute : ElementChildrenAttribute +>children : any + } +} +export function predom(): predom.JSX.Element; +>predom : () => predom.JSX.Element +>predom : any +>JSX : any +>Element : predom.JSX.Element + +=== tests/cases/conformance/jsx/inline/component.tsx === +/** @jsx predom */ +import { predom } from "./renderer2" +>predom : () => predom.JSX.Element + +export default +> : predom.JSX.Element +>h : any +>h : any + +=== tests/cases/conformance/jsx/inline/index.tsx === +/** @jsx dom */ +import { dom } from "./renderer" +>dom : () => JSX.Element + +import prerendered from "./component"; +>prerendered : predom.JSX.Element + +let elem = prerendered; +>elem : predom.JSX.Element +>prerendered : predom.JSX.Element + +elem = ; // Expect assignability error here +>elem = : JSX.Element +>elem : predom.JSX.Element +> : JSX.Element +>h : any +>h : any + diff --git a/tests/baselines/reference/inlineJsxFactoryOverridesCompilerOption.js b/tests/baselines/reference/inlineJsxFactoryOverridesCompilerOption.js new file mode 100644 index 00000000000..fef2e38ee3b --- /dev/null +++ b/tests/baselines/reference/inlineJsxFactoryOverridesCompilerOption.js @@ -0,0 +1,32 @@ +//// [tests/cases/conformance/jsx/inline/inlineJsxFactoryOverridesCompilerOption.tsx] //// + +//// [renderer.d.ts] +declare global { + namespace JSX { + interface IntrinsicElements { + [e: string]: any; + } + } +} +export function dom(): void; +export { dom as p }; +//// [reacty.tsx] +/** @jsx dom */ +import {dom} from "./renderer"; + +//// [index.tsx] +import { p } from "./renderer"; + + + +//// [reacty.js] +"use strict"; +exports.__esModule = true; +/** @jsx dom */ +var renderer_1 = require("./renderer"); +renderer_1.dom("h", null); +//// [index.js] +"use strict"; +exports.__esModule = true; +var renderer_1 = require("./renderer"); +renderer_1.p("h", null); diff --git a/tests/baselines/reference/inlineJsxFactoryOverridesCompilerOption.symbols b/tests/baselines/reference/inlineJsxFactoryOverridesCompilerOption.symbols new file mode 100644 index 00000000000..d3c513c5876 --- /dev/null +++ b/tests/baselines/reference/inlineJsxFactoryOverridesCompilerOption.symbols @@ -0,0 +1,39 @@ +=== tests/cases/conformance/jsx/inline/renderer.d.ts === +declare global { +>global : Symbol(global, Decl(renderer.d.ts, 0, 0)) + + namespace JSX { +>JSX : Symbol(JSX, Decl(renderer.d.ts, 0, 16)) + + interface IntrinsicElements { +>IntrinsicElements : Symbol(IntrinsicElements, Decl(renderer.d.ts, 1, 19)) + + [e: string]: any; +>e : Symbol(e, Decl(renderer.d.ts, 3, 13)) + } + } +} +export function dom(): void; +>dom : Symbol(dom, Decl(renderer.d.ts, 6, 1)) + +export { dom as p }; +>dom : Symbol(p, Decl(renderer.d.ts, 8, 8)) +>p : Symbol(p, Decl(renderer.d.ts, 8, 8)) + +=== tests/cases/conformance/jsx/inline/reacty.tsx === +/** @jsx dom */ +import {dom} from "./renderer"; +>dom : Symbol(dom, Decl(reacty.tsx, 1, 8)) + + +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) + +=== tests/cases/conformance/jsx/inline/index.tsx === +import { p } from "./renderer"; +>p : Symbol(p, Decl(index.tsx, 0, 8)) + + +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) + diff --git a/tests/baselines/reference/inlineJsxFactoryOverridesCompilerOption.types b/tests/baselines/reference/inlineJsxFactoryOverridesCompilerOption.types new file mode 100644 index 00000000000..36b50405dcb --- /dev/null +++ b/tests/baselines/reference/inlineJsxFactoryOverridesCompilerOption.types @@ -0,0 +1,41 @@ +=== tests/cases/conformance/jsx/inline/renderer.d.ts === +declare global { +>global : any + + namespace JSX { +>JSX : any + + interface IntrinsicElements { +>IntrinsicElements : IntrinsicElements + + [e: string]: any; +>e : string + } + } +} +export function dom(): void; +>dom : () => void + +export { dom as p }; +>dom : () => void +>p : () => void + +=== tests/cases/conformance/jsx/inline/reacty.tsx === +/** @jsx dom */ +import {dom} from "./renderer"; +>dom : () => void + + +> : any +>h : any +>h : any + +=== tests/cases/conformance/jsx/inline/index.tsx === +import { p } from "./renderer"; +>p : () => void + + +> : any +>h : any +>h : any + diff --git a/tests/baselines/reference/inlineJsxFactoryWithFragmentIsError.errors.txt b/tests/baselines/reference/inlineJsxFactoryWithFragmentIsError.errors.txt new file mode 100644 index 00000000000..b70ddf5f9b9 --- /dev/null +++ b/tests/baselines/reference/inlineJsxFactoryWithFragmentIsError.errors.txt @@ -0,0 +1,26 @@ +tests/cases/conformance/jsx/inline/index.tsx(3,1): error TS17017: JSX fragment is not supported when using an inline JSX factory pragma +tests/cases/conformance/jsx/inline/reacty.tsx(3,1): error TS17017: JSX fragment is not supported when using an inline JSX factory pragma + + +==== tests/cases/conformance/jsx/inline/renderer.d.ts (0 errors) ==== + declare global { + namespace JSX { + interface IntrinsicElements { + [e: string]: any; + } + } + } + export function dom(): void; + export function createElement(): void; +==== tests/cases/conformance/jsx/inline/reacty.tsx (1 errors) ==== + /** @jsx React.createElement */ + import * as React from "./renderer"; + <> + ~~~~~~~~~~~~ +!!! error TS17017: JSX fragment is not supported when using an inline JSX factory pragma +==== tests/cases/conformance/jsx/inline/index.tsx (1 errors) ==== + /** @jsx dom */ + import { dom } from "./renderer"; + <> + ~~~~~~~~~~~~ +!!! error TS17017: JSX fragment is not supported when using an inline JSX factory pragma \ No newline at end of file diff --git a/tests/baselines/reference/inlineJsxFactoryWithFragmentIsError.js b/tests/baselines/reference/inlineJsxFactoryWithFragmentIsError.js new file mode 100644 index 00000000000..3af54bc04e6 --- /dev/null +++ b/tests/baselines/reference/inlineJsxFactoryWithFragmentIsError.js @@ -0,0 +1,35 @@ +//// [tests/cases/conformance/jsx/inline/inlineJsxFactoryWithFragmentIsError.tsx] //// + +//// [renderer.d.ts] +declare global { + namespace JSX { + interface IntrinsicElements { + [e: string]: any; + } + } +} +export function dom(): void; +export function createElement(): void; +//// [reacty.tsx] +/** @jsx React.createElement */ +import * as React from "./renderer"; +<> +//// [index.tsx] +/** @jsx dom */ +import { dom } from "./renderer"; +<> + +//// [reacty.js] +"use strict"; +exports.__esModule = true; +/** @jsx React.createElement */ +var React = require("./renderer"); +React.createElement(React.Fragment, null, + React.createElement("h", null)); +//// [index.js] +"use strict"; +exports.__esModule = true; +/** @jsx dom */ +var renderer_1 = require("./renderer"); +renderer_1.dom(React.Fragment, null, + renderer_1.dom("h", null)); diff --git a/tests/baselines/reference/inlineJsxFactoryWithFragmentIsError.symbols b/tests/baselines/reference/inlineJsxFactoryWithFragmentIsError.symbols new file mode 100644 index 00000000000..0453bd26105 --- /dev/null +++ b/tests/baselines/reference/inlineJsxFactoryWithFragmentIsError.symbols @@ -0,0 +1,39 @@ +=== tests/cases/conformance/jsx/inline/renderer.d.ts === +declare global { +>global : Symbol(global, Decl(renderer.d.ts, 0, 0)) + + namespace JSX { +>JSX : Symbol(JSX, Decl(renderer.d.ts, 0, 16)) + + interface IntrinsicElements { +>IntrinsicElements : Symbol(IntrinsicElements, Decl(renderer.d.ts, 1, 19)) + + [e: string]: any; +>e : Symbol(e, Decl(renderer.d.ts, 3, 13)) + } + } +} +export function dom(): void; +>dom : Symbol(dom, Decl(renderer.d.ts, 6, 1)) + +export function createElement(): void; +>createElement : Symbol(createElement, Decl(renderer.d.ts, 7, 28)) + +=== tests/cases/conformance/jsx/inline/reacty.tsx === +/** @jsx React.createElement */ +import * as React from "./renderer"; +>React : Symbol(React, Decl(reacty.tsx, 1, 6)) + +<> +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) + +=== tests/cases/conformance/jsx/inline/index.tsx === +/** @jsx dom */ +import { dom } from "./renderer"; +>dom : Symbol(dom, Decl(index.tsx, 1, 8)) + +<> +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) +>h : Symbol(JSX.IntrinsicElements, Decl(renderer.d.ts, 1, 19)) + diff --git a/tests/baselines/reference/inlineJsxFactoryWithFragmentIsError.types b/tests/baselines/reference/inlineJsxFactoryWithFragmentIsError.types new file mode 100644 index 00000000000..e7cd48810b0 --- /dev/null +++ b/tests/baselines/reference/inlineJsxFactoryWithFragmentIsError.types @@ -0,0 +1,43 @@ +=== tests/cases/conformance/jsx/inline/renderer.d.ts === +declare global { +>global : any + + namespace JSX { +>JSX : any + + interface IntrinsicElements { +>IntrinsicElements : IntrinsicElements + + [e: string]: any; +>e : string + } + } +} +export function dom(): void; +>dom : () => void + +export function createElement(): void; +>createElement : () => void + +=== tests/cases/conformance/jsx/inline/reacty.tsx === +/** @jsx React.createElement */ +import * as React from "./renderer"; +>React : typeof React + +<> +><> : any +> : any +>h : any +>h : any + +=== tests/cases/conformance/jsx/inline/index.tsx === +/** @jsx dom */ +import { dom } from "./renderer"; +>dom : () => void + +<> +><> : any +> : any +>h : any +>h : any + diff --git a/tests/baselines/reference/library-reference-5.errors.txt b/tests/baselines/reference/library-reference-5.errors.txt index 173865ed82d..8aead70ff0b 100644 --- a/tests/baselines/reference/library-reference-5.errors.txt +++ b/tests/baselines/reference/library-reference-5.errors.txt @@ -1,4 +1,4 @@ -/node_modules/bar/index.d.ts(1,23): message TS4090: Conflicting definitions for 'alpha' found at '/node_modules/bar/node_modules/alpha/index.d.ts' and '/node_modules/foo/node_modules/alpha/index.d.ts'. Consider installing a specific version of this library to resolve the conflict. +/node_modules/bar/index.d.ts(1,23): error TS4090: Conflicting definitions for 'alpha' found at '/node_modules/bar/node_modules/alpha/index.d.ts' and '/node_modules/foo/node_modules/alpha/index.d.ts'. Consider installing a specific version of this library to resolve the conflict. ==== /src/root.ts (0 errors) ==== @@ -17,7 +17,7 @@ ==== /node_modules/bar/index.d.ts (1 errors) ==== /// ~~~~~ -!!! message TS4090: Conflicting definitions for 'alpha' found at '/node_modules/bar/node_modules/alpha/index.d.ts' and '/node_modules/foo/node_modules/alpha/index.d.ts'. Consider installing a specific version of this library to resolve the conflict. +!!! error TS4090: Conflicting definitions for 'alpha' found at '/node_modules/bar/node_modules/alpha/index.d.ts' and '/node_modules/foo/node_modules/alpha/index.d.ts'. Consider installing a specific version of this library to resolve the conflict. declare var bar: any; ==== /node_modules/bar/node_modules/alpha/index.d.ts (0 errors) ==== diff --git a/tests/baselines/reference/mappedTypeNoTypeNoCrash.errors.txt b/tests/baselines/reference/mappedTypeNoTypeNoCrash.errors.txt new file mode 100644 index 00000000000..1e32656c699 --- /dev/null +++ b/tests/baselines/reference/mappedTypeNoTypeNoCrash.errors.txt @@ -0,0 +1,16 @@ +tests/cases/compiler/mappedTypeNoTypeNoCrash.ts(1,51): error TS2304: Cannot find name 'K'. +tests/cases/compiler/mappedTypeNoTypeNoCrash.ts(1,51): error TS4081: Exported type alias 'T0' has or is using private name 'K'. +tests/cases/compiler/mappedTypeNoTypeNoCrash.ts(1,57): error TS2304: Cannot find name 'K'. +tests/cases/compiler/mappedTypeNoTypeNoCrash.ts(1,57): error TS4081: Exported type alias 'T0' has or is using private name 'K'. + + +==== tests/cases/compiler/mappedTypeNoTypeNoCrash.ts (4 errors) ==== + type T0 = ({[K in keyof T]}) extends ({[key in K]: T[K]}) ? number : never; + ~ +!!! error TS2304: Cannot find name 'K'. + ~ +!!! error TS4081: Exported type alias 'T0' has or is using private name 'K'. + ~ +!!! error TS2304: Cannot find name 'K'. + ~ +!!! error TS4081: Exported type alias 'T0' has or is using private name 'K'. \ No newline at end of file diff --git a/tests/baselines/reference/mappedTypeNoTypeNoCrash.js b/tests/baselines/reference/mappedTypeNoTypeNoCrash.js new file mode 100644 index 00000000000..ad1d9bba0bf --- /dev/null +++ b/tests/baselines/reference/mappedTypeNoTypeNoCrash.js @@ -0,0 +1,4 @@ +//// [mappedTypeNoTypeNoCrash.ts] +type T0 = ({[K in keyof T]}) extends ({[key in K]: T[K]}) ? number : never; + +//// [mappedTypeNoTypeNoCrash.js] diff --git a/tests/baselines/reference/mappedTypeNoTypeNoCrash.symbols b/tests/baselines/reference/mappedTypeNoTypeNoCrash.symbols new file mode 100644 index 00000000000..7faf2d7b35f --- /dev/null +++ b/tests/baselines/reference/mappedTypeNoTypeNoCrash.symbols @@ -0,0 +1,9 @@ +=== tests/cases/compiler/mappedTypeNoTypeNoCrash.ts === +type T0 = ({[K in keyof T]}) extends ({[key in K]: T[K]}) ? number : never; +>T0 : Symbol(T0, Decl(mappedTypeNoTypeNoCrash.ts, 0, 0)) +>T : Symbol(T, Decl(mappedTypeNoTypeNoCrash.ts, 0, 8)) +>K : Symbol(K, Decl(mappedTypeNoTypeNoCrash.ts, 0, 16)) +>T : Symbol(T, Decl(mappedTypeNoTypeNoCrash.ts, 0, 8)) +>key : Symbol(key, Decl(mappedTypeNoTypeNoCrash.ts, 0, 43)) +>T : Symbol(T, Decl(mappedTypeNoTypeNoCrash.ts, 0, 8)) + diff --git a/tests/baselines/reference/mappedTypeNoTypeNoCrash.types b/tests/baselines/reference/mappedTypeNoTypeNoCrash.types new file mode 100644 index 00000000000..0ec1e7723f8 --- /dev/null +++ b/tests/baselines/reference/mappedTypeNoTypeNoCrash.types @@ -0,0 +1,11 @@ +=== tests/cases/compiler/mappedTypeNoTypeNoCrash.ts === +type T0 = ({[K in keyof T]}) extends ({[key in K]: T[K]}) ? number : never; +>T0 : number +>T : T +>K : K +>T : T +>key : key +>K : No type information available! +>T : T +>K : No type information available! + diff --git a/tests/baselines/reference/organizeImports/CoalesceTrivia.ts b/tests/baselines/reference/organizeImports/CoalesceTrivia.ts index 972df9e18eb..536ee4bdd67 100644 --- a/tests/baselines/reference/organizeImports/CoalesceTrivia.ts +++ b/tests/baselines/reference/organizeImports/CoalesceTrivia.ts @@ -10,6 +10,5 @@ F2(); /*A*/ import { /*L*/ F1 /*M*/, /*C*/ F2 /*D*/ } /*E*/ from "lib" /*G*/; /*H*/ //I - F1(); F2(); diff --git a/tests/baselines/reference/organizeImports/SortTrivia.ts b/tests/baselines/reference/organizeImports/SortTrivia.ts index e46c836b966..bbed82c8383 100644 --- a/tests/baselines/reference/organizeImports/SortTrivia.ts +++ b/tests/baselines/reference/organizeImports/SortTrivia.ts @@ -7,4 +7,3 @@ /*F*/ import "lib1" /*H*/; /*I*/ //J /*A*/ import "lib2" /*C*/; /*D*/ //E - diff --git a/tests/baselines/reference/organizeImports/UnusedTrivia2.ts b/tests/baselines/reference/organizeImports/UnusedTrivia2.ts index f853015303e..5575f95fbf4 100644 --- a/tests/baselines/reference/organizeImports/UnusedTrivia2.ts +++ b/tests/baselines/reference/organizeImports/UnusedTrivia2.ts @@ -8,5 +8,4 @@ F1(); /*A*/ import { /*C*/ F1 /*D*/ } /*G*/ from "lib" /*I*/; /*J*/ //K - F1(); diff --git a/tests/baselines/reference/tsxElementResolution16.errors.txt b/tests/baselines/reference/tsxElementResolution16.errors.txt index b68c442c36d..07b2ec54b44 100644 --- a/tests/baselines/reference/tsxElementResolution16.errors.txt +++ b/tests/baselines/reference/tsxElementResolution16.errors.txt @@ -1,8 +1,7 @@ -tests/cases/conformance/jsx/file.tsx(8,1): error TS2602: JSX element implicitly has type 'any' because the global type 'JSX.Element' does not exist. tests/cases/conformance/jsx/file.tsx(8,1): error TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists. -==== tests/cases/conformance/jsx/file.tsx (2 errors) ==== +==== tests/cases/conformance/jsx/file.tsx (1 errors) ==== declare module JSX { } @@ -12,7 +11,5 @@ tests/cases/conformance/jsx/file.tsx(8,1): error TS7026: JSX element implicitly var obj1: Obj1; ; // Error (JSX.Element is implicit any) ~~~~~~~~~~~~~~~ -!!! error TS2602: JSX element implicitly has type 'any' because the global type 'JSX.Element' does not exist. - ~~~~~~~~~~~~~~~ !!! error TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists. \ No newline at end of file diff --git a/tests/baselines/reference/typeGuardOnContainerTypeNoHang.js b/tests/baselines/reference/typeGuardOnContainerTypeNoHang.js new file mode 100644 index 00000000000..238676b7974 --- /dev/null +++ b/tests/baselines/reference/typeGuardOnContainerTypeNoHang.js @@ -0,0 +1,18 @@ +//// [typeGuardOnContainerTypeNoHang.ts] +export namespace TypeGuards { + export function IsObject(value: any) : value is {[index:string]:any} { + return typeof(value) === 'object' + } + +} + +//// [typeGuardOnContainerTypeNoHang.js] +"use strict"; +exports.__esModule = true; +var TypeGuards; +(function (TypeGuards) { + function IsObject(value) { + return typeof (value) === 'object'; + } + TypeGuards.IsObject = IsObject; +})(TypeGuards = exports.TypeGuards || (exports.TypeGuards = {})); diff --git a/tests/baselines/reference/typeGuardOnContainerTypeNoHang.symbols b/tests/baselines/reference/typeGuardOnContainerTypeNoHang.symbols new file mode 100644 index 00000000000..eacc6b7f100 --- /dev/null +++ b/tests/baselines/reference/typeGuardOnContainerTypeNoHang.symbols @@ -0,0 +1,15 @@ +=== tests/cases/compiler/typeGuardOnContainerTypeNoHang.ts === +export namespace TypeGuards { +>TypeGuards : Symbol(TypeGuards, Decl(typeGuardOnContainerTypeNoHang.ts, 0, 0)) + + export function IsObject(value: any) : value is {[index:string]:any} { +>IsObject : Symbol(IsObject, Decl(typeGuardOnContainerTypeNoHang.ts, 0, 29)) +>value : Symbol(value, Decl(typeGuardOnContainerTypeNoHang.ts, 1, 29)) +>value : Symbol(value, Decl(typeGuardOnContainerTypeNoHang.ts, 1, 29)) +>index : Symbol(index, Decl(typeGuardOnContainerTypeNoHang.ts, 1, 54)) + + return typeof(value) === 'object' +>value : Symbol(value, Decl(typeGuardOnContainerTypeNoHang.ts, 1, 29)) + } + +} diff --git a/tests/baselines/reference/typeGuardOnContainerTypeNoHang.types b/tests/baselines/reference/typeGuardOnContainerTypeNoHang.types new file mode 100644 index 00000000000..cc7d90e76df --- /dev/null +++ b/tests/baselines/reference/typeGuardOnContainerTypeNoHang.types @@ -0,0 +1,19 @@ +=== tests/cases/compiler/typeGuardOnContainerTypeNoHang.ts === +export namespace TypeGuards { +>TypeGuards : typeof TypeGuards + + export function IsObject(value: any) : value is {[index:string]:any} { +>IsObject : (value: any) => value is { [index: string]: any; } +>value : any +>value : any +>index : string + + return typeof(value) === 'object' +>typeof(value) === 'object' : boolean +>typeof(value) : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function" +>(value) : any +>value : any +>'object' : "object" + } + +} diff --git a/tests/baselines/reference/typeReferenceDirectives12.trace.json b/tests/baselines/reference/typeReferenceDirectives12.trace.json index 62a3b31fa1c..12f8d938c1d 100644 --- a/tests/baselines/reference/typeReferenceDirectives12.trace.json +++ b/tests/baselines/reference/typeReferenceDirectives12.trace.json @@ -16,7 +16,7 @@ "Resolving real path for '/types/lib/index.d.ts', result '/types/lib/index.d.ts'.", "======== Type reference directive 'lib' was successfully resolved to '/types/lib/index.d.ts', primary: true. ========", "======== Resolving module './main' from '/mod1.ts'. ========", - "Resolution for module './main' was found in cache.", + "Resolution for module './main' was found in cache from location '/'.", "======== Module name './main' was successfully resolved to '/main.ts'. ========", "======== Resolving type reference directive 'lib', containing file '/__inferred type names__.ts', root directory '/types'. ========", "Resolving with primary search path '/types'.", diff --git a/tests/baselines/reference/typeReferenceDirectives9.trace.json b/tests/baselines/reference/typeReferenceDirectives9.trace.json index 62a3b31fa1c..12f8d938c1d 100644 --- a/tests/baselines/reference/typeReferenceDirectives9.trace.json +++ b/tests/baselines/reference/typeReferenceDirectives9.trace.json @@ -16,7 +16,7 @@ "Resolving real path for '/types/lib/index.d.ts', result '/types/lib/index.d.ts'.", "======== Type reference directive 'lib' was successfully resolved to '/types/lib/index.d.ts', primary: true. ========", "======== Resolving module './main' from '/mod1.ts'. ========", - "Resolution for module './main' was found in cache.", + "Resolution for module './main' was found in cache from location '/'.", "======== Module name './main' was successfully resolved to '/main.ts'. ========", "======== Resolving type reference directive 'lib', containing file '/__inferred type names__.ts', root directory '/types'. ========", "Resolving with primary search path '/types'.", diff --git a/tests/cases/compiler/indirectUniqueSymbolDeclarationEmit.ts b/tests/cases/compiler/indirectUniqueSymbolDeclarationEmit.ts new file mode 100644 index 00000000000..5554c5d05c3 --- /dev/null +++ b/tests/cases/compiler/indirectUniqueSymbolDeclarationEmit.ts @@ -0,0 +1,8 @@ +// @lib: es6 +// @declaration: true +export const x = Symbol(); +export const y = Symbol(); +declare function rand(): boolean; +export function f() { + return rand() ? x : y; +} \ No newline at end of file diff --git a/tests/cases/compiler/inferredNonidentifierTypesGetQuotes.ts b/tests/cases/compiler/inferredNonidentifierTypesGetQuotes.ts new file mode 100644 index 00000000000..70e3296bef6 --- /dev/null +++ b/tests/cases/compiler/inferredNonidentifierTypesGetQuotes.ts @@ -0,0 +1,4 @@ +// @declaration: true +var x = [{ "a-b": "string" }, {}]; + +var y = [{ ["a-b"]: "string" }, {}]; \ No newline at end of file diff --git a/tests/cases/compiler/mappedTypeNoTypeNoCrash.ts b/tests/cases/compiler/mappedTypeNoTypeNoCrash.ts new file mode 100644 index 00000000000..fc9760c7a69 --- /dev/null +++ b/tests/cases/compiler/mappedTypeNoTypeNoCrash.ts @@ -0,0 +1,2 @@ +// @declaration: true +type T0 = ({[K in keyof T]}) extends ({[key in K]: T[K]}) ? number : never; \ No newline at end of file diff --git a/tests/cases/compiler/typeGuardOnContainerTypeNoHang.ts b/tests/cases/compiler/typeGuardOnContainerTypeNoHang.ts new file mode 100644 index 00000000000..faab957a4a2 --- /dev/null +++ b/tests/cases/compiler/typeGuardOnContainerTypeNoHang.ts @@ -0,0 +1,6 @@ +export namespace TypeGuards { + export function IsObject(value: any) : value is {[index:string]:any} { + return typeof(value) === 'object' + } + +} \ No newline at end of file diff --git a/tests/cases/conformance/jsx/inline/inlineJsxFactoryDeclarations.tsx b/tests/cases/conformance/jsx/inline/inlineJsxFactoryDeclarations.tsx new file mode 100644 index 00000000000..f574c7e9db9 --- /dev/null +++ b/tests/cases/conformance/jsx/inline/inlineJsxFactoryDeclarations.tsx @@ -0,0 +1,36 @@ +// @jsx: react +// @filename: renderer.d.ts +declare global { + namespace JSX { + interface IntrinsicElements { + [e: string]: any; + } + } +} +export function dom(): void; +export function otherdom(): void; +export function createElement(): void; +export { dom as default }; +// @filename: otherreacty.tsx +/** @jsx React.createElement */ +import * as React from "./renderer"; + +// @filename: other.tsx +/** @jsx h */ +import { dom as h } from "./renderer" +export const prerendered = ; +// @filename: othernoalias.tsx +/** @jsx otherdom */ +import { otherdom } from "./renderer" +export const prerendered2 = ; +// @filename: reacty.tsx +import React from "./renderer" +export const prerendered3 = ; + +// @filename: index.tsx +/** @jsx dom */ +import { dom } from "./renderer" + +export * from "./other"; +export * from "./othernoalias"; +export * from "./reacty"; diff --git a/tests/cases/conformance/jsx/inline/inlineJsxFactoryDeclarationsLocalTypes.tsx b/tests/cases/conformance/jsx/inline/inlineJsxFactoryDeclarationsLocalTypes.tsx new file mode 100644 index 00000000000..009abe2e852 --- /dev/null +++ b/tests/cases/conformance/jsx/inline/inlineJsxFactoryDeclarationsLocalTypes.tsx @@ -0,0 +1,86 @@ +// @jsx: react +// @filename: renderer.d.ts +export namespace dom { + namespace JSX { + interface IntrinsicElements { + [e: string]: {}; + } + interface Element { + __domBrand: void; + props: { + children?: Element[]; + }; + } + interface ElementClass extends Element { + render(): Element; + } + interface ElementAttributesProperty { props: any; } + interface ElementChildrenAttribute { children: any; } + } +} +export function dom(): dom.JSX.Element; +// @filename: renderer2.d.ts +export namespace predom { + namespace JSX { + interface IntrinsicElements { + [e: string]: {}; + } + interface Element { + __predomBrand: void; + props: { + children?: Element[]; + }; + } + interface ElementClass extends Element { + render(): Element; + } + interface ElementAttributesProperty { props: any; } + interface ElementChildrenAttribute { children: any; } + } +} +export function predom(): predom.JSX.Element; +// @filename: component.tsx +/** @jsx predom */ +import { predom } from "./renderer2" + +export const MySFC = (props: {x: number, y: number, children?: predom.JSX.Element[]}) =>

{props.x} + {props.y} = {props.x + props.y}{...this.props.children}

; + +export class MyClass implements predom.JSX.Element { + __predomBrand!: void; + constructor(public props: {x: number, y: number, children?: predom.JSX.Element[]}) {} + render() { + return

+ {this.props.x} + {this.props.y} = {this.props.x + this.props.y} + {...this.props.children} +

; + } +} +export const tree = + +export default + +// @filename: index.tsx +/** @jsx dom */ +import { dom } from "./renderer" +import prerendered, {MySFC, MyClass, tree} from "./component"; +let elem = prerendered; +elem = ; // Expect assignability error here + +const DOMSFC = (props: {x: number, y: number, children?: dom.JSX.Element[]}) =>

{props.x} + {props.y} = {props.x + props.y}{props.children}

; + +class DOMClass implements dom.JSX.Element { + __domBrand!: void; + constructor(public props: {x: number, y: number, children?: dom.JSX.Element[]}) {} + render() { + return

{this.props.x} + {this.props.y} = {this.props.x + this.props.y}{...this.props.children}

; + } +} + +// Should work, everything is a DOM element +const _tree = + +// Should fail, no dom elements +const _brokenTree = + +// Should fail, nondom isn't allowed as children of dom +const _brokenTree2 = {tree}{tree} diff --git a/tests/cases/conformance/jsx/inline/inlineJsxFactoryLocalTypeGlobalFallback.tsx b/tests/cases/conformance/jsx/inline/inlineJsxFactoryLocalTypeGlobalFallback.tsx new file mode 100644 index 00000000000..3f4340f518b --- /dev/null +++ b/tests/cases/conformance/jsx/inline/inlineJsxFactoryLocalTypeGlobalFallback.tsx @@ -0,0 +1,44 @@ +// @jsx: react +// @filename: renderer.d.ts +declare global { + namespace JSX { + interface IntrinsicElements { + [e: string]: {}; + } + interface Element { + __domBrand: void; + children: Element[]; + props: {}; + } + interface ElementAttributesProperty { props: any; } + interface ElementChildrenAttribute { children: any; } + } +} +export function dom(): JSX.Element; +// @filename: renderer2.d.ts +export namespace predom { + namespace JSX { + interface IntrinsicElements { + [e: string]: {}; + } + interface Element { + __predomBrand: void; + children: Element[]; + props: {}; + } + interface ElementAttributesProperty { props: any; } + interface ElementChildrenAttribute { children: any; } + } +} +export function predom(): predom.JSX.Element; +// @filename: component.tsx +/** @jsx predom */ +import { predom } from "./renderer2" +export default + +// @filename: index.tsx +/** @jsx dom */ +import { dom } from "./renderer" +import prerendered from "./component"; +let elem = prerendered; +elem = ; // Expect assignability error here diff --git a/tests/cases/conformance/jsx/inline/inlineJsxFactoryOverridesCompilerOption.tsx b/tests/cases/conformance/jsx/inline/inlineJsxFactoryOverridesCompilerOption.tsx new file mode 100644 index 00000000000..4efd32876ad --- /dev/null +++ b/tests/cases/conformance/jsx/inline/inlineJsxFactoryOverridesCompilerOption.tsx @@ -0,0 +1,19 @@ +// @jsx: react +// @jsxFactory: p +// @filename: renderer.d.ts +declare global { + namespace JSX { + interface IntrinsicElements { + [e: string]: any; + } + } +} +export function dom(): void; +export { dom as p }; +// @filename: reacty.tsx +/** @jsx dom */ +import {dom} from "./renderer"; + +// @filename: index.tsx +import { p } from "./renderer"; + diff --git a/tests/cases/conformance/jsx/inline/inlineJsxFactoryWithFragmentIsError.tsx b/tests/cases/conformance/jsx/inline/inlineJsxFactoryWithFragmentIsError.tsx new file mode 100644 index 00000000000..280ac26b5ce --- /dev/null +++ b/tests/cases/conformance/jsx/inline/inlineJsxFactoryWithFragmentIsError.tsx @@ -0,0 +1,19 @@ +// @jsx: react +// @filename: renderer.d.ts +declare global { + namespace JSX { + interface IntrinsicElements { + [e: string]: any; + } + } +} +export function dom(): void; +export function createElement(): void; +// @filename: reacty.tsx +/** @jsx React.createElement */ +import * as React from "./renderer"; +<> +// @filename: index.tsx +/** @jsx dom */ +import { dom } from "./renderer"; +<> \ No newline at end of file diff --git a/tests/cases/fourslash/findAllRefsForModule.ts b/tests/cases/fourslash/findAllRefsForModule.ts index bff3aa17785..a8641625075 100644 --- a/tests/cases/fourslash/findAllRefsForModule.ts +++ b/tests/cases/fourslash/findAllRefsForModule.ts @@ -14,8 +14,6 @@ // @Filename: /d.ts //// /// -verify.noErrors(); - const ranges = test.ranges(); const [r0, r1, r2] = ranges; verify.referenceGroups(ranges, [{ definition: 'module "/a"', ranges: [r0, r2, r1] }]); diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 4d537661a27..7561ca3793d 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -347,8 +347,9 @@ declare namespace FourSlashInterface { start: number; length: number; }, displayParts: ts.SymbolDisplayPart[], documentation: ts.SymbolDisplayPart[], tags: ts.JSDocTagInfo[]): void; - getSyntacticDiagnostics(expected: string): void; - getSemanticDiagnostics(expected: string): void; + getSyntacticDiagnostics(expected: ReadonlyArray): void; + getSemanticDiagnostics(expected: ReadonlyArray): void; + getSuggestionDiagnostics(expected: ReadonlyArray): void; ProjectInfo(expected: string[]): void; allRangesAppearInImplementationList(markerName: string): void; } @@ -520,6 +521,13 @@ declare namespace FourSlashInterface { text: string; range: Range; } + interface RealizedDiagnostic { + message: string; + start: number; + length: number; + category: string; + code: number; + } } declare function verifyOperationIsCancelled(f: any): void; declare var test: FourSlashInterface.test_; diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics1.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics1.ts index 8c151742b75..20ca5101ba8 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics1.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics1.ts @@ -4,12 +4,12 @@ // @Filename: a.js //// import a = b; -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "'import ... =' can only be used in a .ts file.", - "start": 0, - "length": 13, - "category": "error", - "code": 8002 + message: "'import ... =' can only be used in a .ts file.", + start: 0, + length: 13, + category: "error", + code: 8002 } -]`); \ No newline at end of file +]); \ No newline at end of file diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics10.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics10.ts index 206c1a6e2cf..fb9d68336e0 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics10.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics10.ts @@ -4,12 +4,12 @@ // @Filename: a.js //// function F() { } -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "'type parameter declarations' can only be used in a .ts file.", - "start": 11, - "length": 1, - "category": "error", - "code": 8004 + message: "'type parameter declarations' can only be used in a .ts file.", + start: 11, + length: 1, + category: "error", + code: 8004 } -]`); \ No newline at end of file +]); diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics11.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics11.ts index d9b1d35b5c6..4a5dafd1042 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics11.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics11.ts @@ -4,12 +4,12 @@ // @Filename: a.js //// function F(): number { } -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "'types' can only be used in a .ts file.", - "start": 14, - "length": 6, - "category": "error", - "code": 8010 + message: "'types' can only be used in a .ts file.", + start: 14, + length: 6, + category: "error", + code: 8010 } -]`); \ No newline at end of file +]); diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics12.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics12.ts index cf244f7cfa2..fc7956d73c9 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics12.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics12.ts @@ -4,12 +4,12 @@ // @Filename: a.js //// declare var v; -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "'declare' can only be used in a .ts file.", - "start": 0, - "length": 7, - "category": "error", - "code": 8009 + message: "'declare' can only be used in a .ts file.", + start: 0, + length: 7, + category: "error", + code: 8009 } -]`); \ No newline at end of file +]); diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics13.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics13.ts index aaf3289fcfe..87cc7b37867 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics13.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics13.ts @@ -4,12 +4,12 @@ // @Filename: a.js //// var v: () => number; -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "'types' can only be used in a .ts file.", - "start": 7, - "length": 12, - "category": "error", - "code": 8010 + message: "'types' can only be used in a .ts file.", + start: 7, + length: 12, + category: "error", + code: 8010 } -]`); \ No newline at end of file +]); \ No newline at end of file diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics14.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics14.ts index a41d88dd675..4659897559c 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics14.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics14.ts @@ -4,12 +4,12 @@ // @Filename: a.js //// Foo(); -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "'type arguments' can only be used in a .ts file.", - "start": 4, - "length": 6, - "category": "error", - "code": 8011 + message: "'type arguments' can only be used in a .ts file.", + start: 4, + length: 6, + category: "error", + code: 8011 } -]`); \ No newline at end of file +]); diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics15.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics15.ts index 93430a9a004..31194e37fcb 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics15.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics15.ts @@ -4,12 +4,12 @@ // @Filename: a.js //// function F(public p) { } -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "'parameter modifiers' can only be used in a .ts file.", - "start": 11, - "length": 6, - "category": "error", - "code": 8012 + message: "'parameter modifiers' can only be used in a .ts file.", + start: 11, + length: 6, + category: "error", + code: 8012 } -]`); \ No newline at end of file +]); \ No newline at end of file diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics16.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics16.ts index 60e0684b106..4d4e3a56287 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics16.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics16.ts @@ -4,12 +4,12 @@ // @Filename: a.js //// function F(p?) { } -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "'?' can only be used in a .ts file.", - "start": 12, - "length": 1, - "category": "error", - "code": 8009 + message: "'?' can only be used in a .ts file.", + start: 12, + length: 1, + category: "error", + code: 8009 } -]`); \ No newline at end of file +]); \ No newline at end of file diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics17.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics17.ts index 3a57917b2ac..f6d4d65a83d 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics17.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics17.ts @@ -4,12 +4,12 @@ // @Filename: a.js //// function F(a: number) { } -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "'types' can only be used in a .ts file.", - "start": 14, - "length": 6, - "category": "error", - "code": 8010 + message: "'types' can only be used in a .ts file.", + start: 14, + length: 6, + category: "error", + code: 8010 } -]`); \ No newline at end of file +]); \ No newline at end of file diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics18.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics18.ts index d253cb63611..71e098b0ee2 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics18.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics18.ts @@ -9,15 +9,15 @@ ////} goTo.file("a.js"); -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "\'public\' can only be used in a .ts file.", - "start": 93, - "length": 6, - "category": "error", - "code": 8009 + message: "\'public\' can only be used in a .ts file.", + start: 93, + length: 6, + category: "error", + code: 8009 } -]`); +]); // @Filename: b.js ////class C { @@ -25,12 +25,12 @@ verify.getSyntacticDiagnostics(`[ ////} goTo.file("b.js"); -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "'types' can only be used in a .ts file.", - "start": 17, - "length": 6, - "category": "error", - "code": 8010 + message: "'types' can only be used in a .ts file.", + start: 17, + length: 6, + category: "error", + code: 8010 } -]`); +]); diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics19.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics19.ts index 7729a6ea470..fe602056dcb 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics19.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics19.ts @@ -4,12 +4,12 @@ // @Filename: a.js //// enum E { } -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "'enum declarations' can only be used in a .ts file.", - "start": 5, - "length": 1, - "category": "error", - "code": 8015 + message: "'enum declarations' can only be used in a .ts file.", + start: 5, + length: 1, + category: "error", + code: 8015 } -]`); \ No newline at end of file +]); \ No newline at end of file diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics2.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics2.ts index 74e6a9ab089..0a14c8b5ddf 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics2.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics2.ts @@ -4,12 +4,12 @@ // @Filename: a.js //// export = b; -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "'export=' can only be used in a .ts file.", - "start": 0, - "length": 11, - "category": "error", - "code": 8003 + message: "'export=' can only be used in a .ts file.", + start: 0, + length: 11, + category: "error", + code: 8003 } -]`); \ No newline at end of file +]); \ No newline at end of file diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics21.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics21.ts index 8a7120acbb3..b6dc7d3df51 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics21.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics21.ts @@ -5,4 +5,4 @@ // @Filename: a.js //// @internal class C {} -verify.getSemanticDiagnostics(`[]`); +verify.getSemanticDiagnostics([]); diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics22.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics22.ts index d4d830d29e9..dc4779eef07 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics22.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics22.ts @@ -4,4 +4,4 @@ // @Filename: a.js //// function foo(...a) {} -verify.getSemanticDiagnostics(`[]`); +verify.getSemanticDiagnostics([]); diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics23.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics23.ts index 2524e50e668..a8271dce596 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics23.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics23.ts @@ -10,5 +10,5 @@ //// } //// } -verify.getSyntacticDiagnostics(`[]`); -verify.getSemanticDiagnostics(`[]`); +verify.getSyntacticDiagnostics([]); +verify.getSemanticDiagnostics([]); diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics3.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics3.ts index 3528f333329..47837864781 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics3.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics3.ts @@ -4,12 +4,12 @@ // @Filename: a.js //// class C { } -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "'type parameter declarations' can only be used in a .ts file.", - "start": 8, - "length": 1, - "category": "error", - "code": 8004 + message: "'type parameter declarations' can only be used in a .ts file.", + start: 8, + length: 1, + category: "error", + code: 8004 } -]`); \ No newline at end of file +]); \ No newline at end of file diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics4.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics4.ts index 3b849b08ae0..efd8fe85964 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics4.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics4.ts @@ -4,12 +4,12 @@ // @Filename: a.js //// public class C { } -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "'public' can only be used in a .ts file.", - "start": 0, - "length": 6, - "category": "error", - "code": 8009 + message: "'public' can only be used in a .ts file.", + start: 0, + length: 6, + category: "error", + code: 8009 } -]`); \ No newline at end of file +]); \ No newline at end of file diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics5.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics5.ts index 985e3284025..0fcc7652101 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics5.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics5.ts @@ -4,12 +4,12 @@ // @Filename: a.js //// class C implements D { } -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "'implements clauses' can only be used in a .ts file.", - "start": 8, - "length": 12, - "category": "error", - "code": 8005 + message: "'implements clauses' can only be used in a .ts file.", + start: 8, + length: 12, + category: "error", + code: 8005 } -]`); \ No newline at end of file +]); \ No newline at end of file diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics6.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics6.ts index a0042a0529b..6d4c7e7dcca 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics6.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics6.ts @@ -4,12 +4,12 @@ // @Filename: a.js //// interface I { } -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "'interface declarations' can only be used in a .ts file.", - "start": 10, - "length": 1, - "category": "error", - "code": 8006 + message: "'interface declarations' can only be used in a .ts file.", + start: 10, + length: 1, + category: "error", + code: 8006 } -]`); \ No newline at end of file +]); \ No newline at end of file diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics7.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics7.ts index 64216d1e364..32ebf6bde0d 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics7.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics7.ts @@ -4,12 +4,12 @@ // @Filename: a.js //// module M { } -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "'module declarations' can only be used in a .ts file.", - "start": 7, - "length": 1, - "category": "error", - "code": 8007 + message: "'module declarations' can only be used in a .ts file.", + start: 7, + length: 1, + category: "error", + code: 8007 } -]`); \ No newline at end of file +]); \ No newline at end of file diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics8.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics8.ts index 296f4f7445e..7ab0db792e8 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics8.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics8.ts @@ -4,12 +4,12 @@ // @Filename: a.js //// type a = b; -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "'type aliases' can only be used in a .ts file.", - "start": 5, - "length": 1, - "category": "error", - "code": 8008 + message: "'type aliases' can only be used in a .ts file.", + start: 5, + length: 1, + category: "error", + code: 8008 } -]`); \ No newline at end of file +]); \ No newline at end of file diff --git a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics9.ts b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics9.ts index f2c20a52ee9..c18f32e378e 100644 --- a/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics9.ts +++ b/tests/cases/fourslash/getJavaScriptSyntacticDiagnostics9.ts @@ -4,12 +4,12 @@ // @Filename: a.js //// public function F() { } -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "'public' can only be used in a .ts file.", - "start": 0, - "length": 6, - "category": "error", - "code": 8009 + message: "'public' can only be used in a .ts file.", + start: 0, + length: 6, + category: "error", + code: 8009 } -]`); \ No newline at end of file +]); \ No newline at end of file diff --git a/tests/cases/fourslash/jsDocAugmentsAndExtends.ts b/tests/cases/fourslash/jsDocAugmentsAndExtends.ts index 10f33260268..ca703f33025 100644 --- a/tests/cases/fourslash/jsDocAugmentsAndExtends.ts +++ b/tests/cases/fourslash/jsDocAugmentsAndExtends.ts @@ -25,13 +25,10 @@ goTo.marker(); verify.quickInfoIs("(local var) x: number"); -verify.getSemanticDiagnostics( -`[ - { - "message": "Class declarations cannot have more than one \`@augments\` or \`@extends\` tag.", - "start": 36, - "length": 24, - "category": "error", - "code": 8025 - } -]`); \ No newline at end of file +verify.getSemanticDiagnostics([{ + message: "Class declarations cannot have more than one \`@augments\` or \`@extends\` tag.", + start: 36, + length: 24, + category: "error", + code: 8025 +}]); diff --git a/tests/cases/fourslash/jsFileCompilationDuplicateFunctionImplementation.ts b/tests/cases/fourslash/jsFileCompilationDuplicateFunctionImplementation.ts index 00d03b6e60c..115964b40f0 100644 --- a/tests/cases/fourslash/jsFileCompilationDuplicateFunctionImplementation.ts +++ b/tests/cases/fourslash/jsFileCompilationDuplicateFunctionImplementation.ts @@ -12,13 +12,25 @@ ////function foo() { return 30; }/*2*/ goTo.marker("1"); -verify.getSemanticDiagnostics('[]'); +verify.getSemanticDiagnostics([]); goTo.marker("2"); -verify.getSemanticDiagnostics('[\n {\n "message": "Duplicate function implementation.",\n "start": 9,\n "length": 3,\n "category": "error",\n "code": 2393\n }\n]'); +verify.getSemanticDiagnostics([{ + message: "Duplicate function implementation.", + start: 9, + length: 3, + category: "error", + code: 2393 +}]); verify.verifyGetEmitOutputContentsForCurrentFile([ { name: "out.js", text: "function foo() { return 10; }\r\nfunction foo() { return 30; }\r\n", writeByteOrderMark: false }, { name: "out.d.ts", text: "", writeByteOrderMark: false }]); goTo.marker("2"); -verify.getSemanticDiagnostics('[\n {\n "message": "Duplicate function implementation.",\n "start": 9,\n "length": 3,\n "category": "error",\n "code": 2393\n }\n]'); +verify.getSemanticDiagnostics([{ + message: "Duplicate function implementation.", + start: 9, + length: 3, + category: "error", + code: 2393 +}]); goTo.marker("1"); -verify.getSemanticDiagnostics('[]'); \ No newline at end of file +verify.getSemanticDiagnostics([]); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_export_alias.ts b/tests/cases/fourslash/refactorConvertToEs6Module_export_alias.ts index 6529bb64af0..73cd606adf9 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_export_alias.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_export_alias.ts @@ -5,14 +5,11 @@ // @Filename: /a.js ////const exportsAlias = exports; ////exportsAlias.f = function() {}; -/////*a*/module/*b*/.exports = exportsAlias; +////module.exports = exportsAlias; -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: ` +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: ` export function f() { } `, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_export_dotDefault.ts b/tests/cases/fourslash/refactorConvertToEs6Module_export_dotDefault.ts index 1c8633eb4eb..1283b0053a8 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_export_dotDefault.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_export_dotDefault.ts @@ -5,15 +5,13 @@ // @allowJs: true // @Filename: /a.js -/////*a*/exports/*b*/.default = 0; +////exports.default = 0; ////exports.default; -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: `const _default = 0; +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: +`const _default = 0; export { _default as default }; _default;`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_export_invalidName.ts b/tests/cases/fourslash/refactorConvertToEs6Module_export_invalidName.ts index 16b48fcd204..83a831effb0 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_export_invalidName.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_export_invalidName.ts @@ -5,15 +5,13 @@ // @allowJs: true // @Filename: /a.js -/////*a*/exports/*b*/.class = 0; +////exports.class = 0; ////exports.async = 1; -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: `const _class = 0; +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: +`const _class = 0; export { _class as class }; export const async = 1;`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_export_moduleDotExports.ts b/tests/cases/fourslash/refactorConvertToEs6Module_export_moduleDotExports.ts index ddcf79d0114..3382228babb 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_export_moduleDotExports.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_export_moduleDotExports.ts @@ -3,7 +3,7 @@ // @allowJs: true // @Filename: /a.js -/////*a*/module/*b*/.exports = function() {} +////module.exports = function() {} ////module.exports = function f() {} ////module.exports = class {} ////module.exports = class C {} @@ -11,16 +11,14 @@ // See also `refactorConvertToEs6Module_export_moduleDotExportsEqualsRequire.ts` -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: `export default function() { } +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: +`export default function() { } export default function f() { } export default class { } export default class C { } -export default 0;` +export default 0;`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_export_moduleDotExportsEqualsRequire.ts b/tests/cases/fourslash/refactorConvertToEs6Module_export_moduleDotExportsEqualsRequire.ts index 8d22ea77c2b..81877c8a98b 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_export_moduleDotExportsEqualsRequire.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_export_moduleDotExportsEqualsRequire.ts @@ -18,7 +18,7 @@ // @Filename: /z.js // Normally -- just `export *` -/////*a*/module/*b*/.exports = require("./a"); +////module.exports = require("./a"); // If just a default is exported, just `export { default }` ////module.exports = require("./b"); // May need both @@ -28,12 +28,10 @@ // In untyped case just go with `export *` ////module.exports = require("./unknown"); -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: +goTo.file("/z.js"); +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: `export * from "./a"; export { default } from "./b"; export * from "./c"; diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_export_moduleDotExports_changesImports.ts b/tests/cases/fourslash/refactorConvertToEs6Module_export_moduleDotExports_changesImports.ts index 7b48bd5f91e..84f081d24b3 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_export_moduleDotExports_changesImports.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_export_moduleDotExports_changesImports.ts @@ -3,7 +3,7 @@ // @allowJs: true // @Filename: /a.js -/////*a*/module/*b*/.exports = 0; +////module.exports = 0; // @Filename: /b.ts ////import a = require("./a"); @@ -11,12 +11,9 @@ // @Filename: /c.js ////const a = require("./a"); -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: `export default 0;`, +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: "export default 0;", }); goTo.file("/b.ts"); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_export_named.ts b/tests/cases/fourslash/refactorConvertToEs6Module_export_named.ts index 8251f90fc0d..03303b1e09e 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_export_named.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_export_named.ts @@ -3,16 +3,22 @@ // @allowJs: true // @Filename: /a.js -/////*a*/exports/*b*/.f = function() {} +////exports.f = function() {}/*diagEnd*/ ////exports.C = class {} ////exports.x = 0; -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: `export function f() { } +verify.getSuggestionDiagnostics([{ + message: "File is a CommonJS module; it may be converted to an ES6 module.", + start: 0, + length: test.marker("diagEnd").position, + category: "suggestion", + code: 80001, +}]); + +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: +`export function f() { } export class C { } export const x = 0;`, diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_export_namedFunctionExpression.ts b/tests/cases/fourslash/refactorConvertToEs6Module_export_namedFunctionExpression.ts index a4b0ba24109..dbd4e6a0a4c 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_export_namedFunctionExpression.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_export_namedFunctionExpression.ts @@ -3,15 +3,12 @@ // @allowJs: true // @Filename: /a.js -/////*a*/exports/*b*/.f = function g() { g(); } +////exports.f = function g() { g(); } ////exports.h = function h() { h(); } -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: `export const f = function g() { g(); }; -export function h() { h(); }` +export function h() { h(); }`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_export_object.ts b/tests/cases/fourslash/refactorConvertToEs6Module_export_object.ts index b18bc94579d..61c46c98b3c 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_export_object.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_export_object.ts @@ -3,7 +3,7 @@ // @allowJs: true // @Filename: /a.js -/////*a*/module/*b*/.exports = { +////module.exports = { //// x: 0, //// f: function() {}, //// g: () => {}, @@ -11,12 +11,10 @@ //// C: class {}, ////}; -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: `export const x = 0; +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: +`export const x = 0; export function f() { } export function g() { } export function h() { } diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_export_object_shorthand.ts b/tests/cases/fourslash/refactorConvertToEs6Module_export_object_shorthand.ts index 05b4903eda3..f6fe1048820 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_export_object_shorthand.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_export_object_shorthand.ts @@ -6,13 +6,11 @@ // @Filename: /a.js ////function f() {} -/////*a*/module/*b*/.exports = { f }; +////module.exports = { f }; -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: `function f() {} +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: +`function f() {} export default { f };`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_export_referenced.ts b/tests/cases/fourslash/refactorConvertToEs6Module_export_referenced.ts index da9976fa7d0..ff87d3c6948 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_export_referenced.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_export_referenced.ts @@ -7,7 +7,7 @@ ////exports.x; //// ////const y = 1; -/////*a*/exports/*b*/.y = y; +////exports.y = y; ////exports.y; //// ////exports.z = 2; @@ -15,12 +15,10 @@ //// exports.z; ////} -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: `export const x = 0; +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: +`export const x = 0; x; const y = 1; diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_expressionToDeclaration.ts b/tests/cases/fourslash/refactorConvertToEs6Module_expressionToDeclaration.ts index b3b7fbf94c6..746524e849c 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_expressionToDeclaration.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_expressionToDeclaration.ts @@ -3,15 +3,13 @@ // @allowJs: true // @Filename: /a.js -/////*a*/exports/*b*/.f = async function* f(p) {} +////exports.f = async function* f(p) {} ////exports.C = class C extends D { m() {} } -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: `export async function* f(p) { } +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: +`export async function* f(p) { } export class C extends D { m() { } }`, diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_import_arrayBindingPattern.ts b/tests/cases/fourslash/refactorConvertToEs6Module_import_arrayBindingPattern.ts index b33b0a1a160..d7e857b5d5e 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_import_arrayBindingPattern.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_import_arrayBindingPattern.ts @@ -5,11 +5,8 @@ // @Filename: /a.js ////const [x, y] = /*a*/require/*b*/("x"); -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: `import _x from "x"; +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: `import _x from "x"; const [x, y] = _x;`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_import_includeDefaultUses.ts b/tests/cases/fourslash/refactorConvertToEs6Module_import_includeDefaultUses.ts index 7c5415c1451..0e69f9519ee 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_import_includeDefaultUses.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_import_includeDefaultUses.ts @@ -7,12 +7,10 @@ ////x(); ////x.y; -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: `import x, { y } from "x"; +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: +`import x, { y } from "x"; x(); y;`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_import_multipleUniqueIdentifiers.ts b/tests/cases/fourslash/refactorConvertToEs6Module_import_multipleUniqueIdentifiers.ts index 321a9cccf8b..a42f1fe5321 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_import_multipleUniqueIdentifiers.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_import_multipleUniqueIdentifiers.ts @@ -4,17 +4,15 @@ // @Filename: /a.js ////const x = require("x"); -////const [a, b] = /*a*/require/*b*/("x"); +////const [a, b] = require("x"); ////const {c, ...d} = require("x"); -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: `import x from "x"; +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: +`import x from "x"; import _x from "x"; const [a, b] = _x; import __x from "x"; -const { c, ...d } = __x;` +const { c, ...d } = __x;`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_import_multipleVariableDeclarations.ts b/tests/cases/fourslash/refactorConvertToEs6Module_import_multipleVariableDeclarations.ts index 37d65ddc622..3c45950c90d 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_import_multipleVariableDeclarations.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_import_multipleVariableDeclarations.ts @@ -5,14 +5,12 @@ // @allowJs: true // @Filename: /a.js -////const x = /*a*/require/*b*/("x"), y = 0, { z } = require("z"); +////const x = require("x"), y = 0, { z } = require("z"); -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: `import x from "x"; +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: +`import x from "x"; const y = 0; import { z } from "z";`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_import_nameFromModuleSpecifier.ts b/tests/cases/fourslash/refactorConvertToEs6Module_import_nameFromModuleSpecifier.ts index 0c953b2e7e6..510b610315a 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_import_nameFromModuleSpecifier.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_import_nameFromModuleSpecifier.ts @@ -3,19 +3,17 @@ // @allowJs: true // @Filename: /a.js -////const [] = /*a0*/require/*b0*/("a-b"); -////const [] = /*a1*/require/*b1*/("0a"); -////const [] = /*a2*/require/*b2*/("1a"); +////const [] = require("a-b"); +////const [] = require("0a"); +////const [] = require("1a"); -goTo.select("a0", "b0"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: `import aB from "a-b"; +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: +`import aB from "a-b"; const [] = aB; import A from "0a"; const [] = A; import _A from "1a"; -const [] = _A;` +const [] = _A;`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_import_objectBindingPattern_complex.ts b/tests/cases/fourslash/refactorConvertToEs6Module_import_objectBindingPattern_complex.ts index f757db2164a..32df9906964 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_import_objectBindingPattern_complex.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_import_objectBindingPattern_complex.ts @@ -3,13 +3,11 @@ // @allowJs: true // @Filename: /a.js -////const { x: { a, b } } = /*a*/require/*b*/("x"); +////const { x: { a, b } } = require("x"); -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: `import x from "x"; +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: +`import x from "x"; const { x: { a, b } } = x;`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_import_objectBindingPattern_plain.ts b/tests/cases/fourslash/refactorConvertToEs6Module_import_objectBindingPattern_plain.ts index 474fd4b0f0f..4bff560e530 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_import_objectBindingPattern_plain.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_import_objectBindingPattern_plain.ts @@ -3,12 +3,9 @@ // @allowJs: true // @Filename: /a.js -////const { x, y: z } = /*a*/require/*b*/("x"); +////const { x, y: z } = require("x"); -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: 'import { x, y as z } from "x";', +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: 'import { x, y as z } from "x";', }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_import_onlyNamedImports.ts b/tests/cases/fourslash/refactorConvertToEs6Module_import_onlyNamedImports.ts index bf7e207550e..7f66b67685e 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_import_onlyNamedImports.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_import_onlyNamedImports.ts @@ -3,14 +3,12 @@ // @allowJs: true // @Filename: /a.js -////const x = /*a*/require/*b*/("x"); +////const x = require("x"); ////x.y; -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: `import { y } from "x"; +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: +`import { y } from "x"; y;`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_import_propertyAccess.ts b/tests/cases/fourslash/refactorConvertToEs6Module_import_propertyAccess.ts index 57efd5370f2..34c6ee6aa57 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_import_propertyAccess.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_import_propertyAccess.ts @@ -3,18 +3,16 @@ // @allowJs: true // @Filename: /a.js -////const x = /*a*/require/*b*/("x").default; +////const x = require("x").default; ////const a = require("b").c; ////const a = require("a").a; ////const [a, b] = require("c").d; ////const [a, b] = require("c").a; // Test that we avoid shadowing the earlier local variable 'a' from 'const [a,b] = d;'. -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: `import x from "x"; +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: +`import x from "x"; import { c as a } from "b"; import { a } from "a"; import { d } from "c"; diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_import_shadowing.ts b/tests/cases/fourslash/refactorConvertToEs6Module_import_shadowing.ts index c389280d75c..dec87859901 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_import_shadowing.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_import_shadowing.ts @@ -3,16 +3,14 @@ // @allowJs: true // @Filename: /a.js -////const mod = /*a*/require/*b*/("mod"); +////const mod = require("mod"); ////const x = 0; ////mod.x(x); -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: `import { x as _x } from "mod"; +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: +`import { x as _x } from "mod"; const x = 0; -_x(x);` +_x(x);`, }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_import_sideEffect.ts b/tests/cases/fourslash/refactorConvertToEs6Module_import_sideEffect.ts index 2b81c816e20..f729f0a9815 100644 --- a/tests/cases/fourslash/refactorConvertToEs6Module_import_sideEffect.ts +++ b/tests/cases/fourslash/refactorConvertToEs6Module_import_sideEffect.ts @@ -7,10 +7,7 @@ // @Filename: /a.js /////*a*/require/*b*/("foo"); -goTo.select("a", "b"); -edit.applyRefactor({ - refactorName: "Convert to ES6 module", - actionName: "Convert to ES6 module", - actionDescription: "Convert to ES6 module", - newContent: 'import "foo";', +verify.codeFix({ + description: "Convert to ES6 module", + newFileContent: 'import "foo";', }); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_triggers.ts b/tests/cases/fourslash/refactorConvertToEs6Module_triggers.ts deleted file mode 100644 index 8d441f47dc3..00000000000 --- a/tests/cases/fourslash/refactorConvertToEs6Module_triggers.ts +++ /dev/null @@ -1,13 +0,0 @@ -/// - -// @allowJs: true - -// @Filename: /a.js -////c[|o|]nst [|a|]lias [|=|] [|m|]odule[|.|]export[|s|]; -////[|a|]lias[|.|][|x|] = 0; -////[|module.exports|]; -////[|require("x")|]; -////[|require("x").y;|]; - -goTo.eachRange(() => verify.refactorAvailable("Convert to ES6 module")); - diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_triggers_declarationList.ts b/tests/cases/fourslash/refactorConvertToEs6Module_triggers_declarationList.ts deleted file mode 100644 index 36ec32b0561..00000000000 --- a/tests/cases/fourslash/refactorConvertToEs6Module_triggers_declarationList.ts +++ /dev/null @@ -1,9 +0,0 @@ -/// - -// @allowJs: true - -// @Filename: /a.js -////c[|o|]nst; -////require("x"); - -goTo.eachRange(() => verify.not.refactorAvailable("Convert to ES6 module")); diff --git a/tests/cases/fourslash/refactorConvertToEs6Module_triggers_noInitializer.ts b/tests/cases/fourslash/refactorConvertToEs6Module_triggers_noInitializer.ts deleted file mode 100644 index 23cbdd12aee..00000000000 --- a/tests/cases/fourslash/refactorConvertToEs6Module_triggers_noInitializer.ts +++ /dev/null @@ -1,11 +0,0 @@ -/// - -// @allowJs: true - -// @Filename: /a.js -/////*a*/const/*b*/ alias; -////require("x"); - -goTo.select("a", "b"); -verify.not.refactorAvailable("Convert to ES6 module"); - diff --git a/tests/cases/fourslash/server/getJavaScriptSyntacticDiagnostics01.ts b/tests/cases/fourslash/server/getJavaScriptSyntacticDiagnostics01.ts index 0aa88ebd90c..d06395186e4 100644 --- a/tests/cases/fourslash/server/getJavaScriptSyntacticDiagnostics01.ts +++ b/tests/cases/fourslash/server/getJavaScriptSyntacticDiagnostics01.ts @@ -4,20 +4,20 @@ // @Filename: a.js //// var ===; -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "Variable declaration expected.", - "start": 4, - "length": 3, - "category": "error", - "code": 1134 + message: "Variable declaration expected.", + start: 4, + length: 3, + category: "error", + code: 1134 }, { - "message": "Expression expected.", - "start": 7, - "length": 1, - "category": "error", - "code": 1109 - } -]`); -verify.getSemanticDiagnostics(`[]`); \ No newline at end of file + message: "Expression expected.", + start: 7, + length: 1, + category: "error", + code: 1109 + }, +]); +verify.getSemanticDiagnostics([]); diff --git a/tests/cases/fourslash/server/getJavaScriptSyntacticDiagnostics02.ts b/tests/cases/fourslash/server/getJavaScriptSyntacticDiagnostics02.ts index a19d170217c..ab12a5c146d 100644 --- a/tests/cases/fourslash/server/getJavaScriptSyntacticDiagnostics02.ts +++ b/tests/cases/fourslash/server/getJavaScriptSyntacticDiagnostics02.ts @@ -7,41 +7,41 @@ //// function foo(): string { } //// var var = "c"; -verify.getSyntacticDiagnostics(`[ +verify.getSyntacticDiagnostics([ { - "message": "\'types\' can only be used in a .ts file.", - "start": 20, - "length": 7, - "category": "error", - "code": 8010 + message: "'types' can only be used in a .ts file.", + start: 20, + length: 7, + category: "error", + code: 8010 }, { - "message": "\'types\' can only be used in a .ts file.", - "start": 52, - "length": 6, - "category": "error", - "code": 8010 + message: "\'types\' can only be used in a .ts file.", + start: 52, + length: 6, + category: "error", + code: 8010 }, { - "message": "Variable declaration expected.", - "start": 67, - "length": 3, - "category": "error", - "code": 1134 + message: "Variable declaration expected.", + start: 67, + length: 3, + category: "error", + code: 1134 }, { - "message": "Variable declaration expected.", - "start": 71, - "length": 1, - "category": "error", - "code": 1134 + message: "Variable declaration expected.", + start: 71, + length: 1, + category: "error", + code: 1134 }, { - "message": "Variable declaration expected.", - "start": 73, - "length": 3, - "category": "error", - "code": 1134 - } -]`); -verify.getSemanticDiagnostics(`[]`); \ No newline at end of file + message: "Variable declaration expected.", + start: 73, + length: 3, + category: "error", + code: 1134 + }, +]); +verify.getSemanticDiagnostics([]);