From 4196c1498e0507932cf785580138b7cdd3a0b1d9 Mon Sep 17 00:00:00 2001 From: Triston Armstrong Date: Mon, 14 Oct 2024 06:49:14 -0400 Subject: [PATCH 1/2] getting majority of things implimented --- src/compiler/checker.ts | 120 ++++++++- src/compiler/diagnosticMessages.json | 14 ++ src/compiler/factory/nodeFactory.ts | 7 + src/compiler/factory/nodeTests.ts | 6 + src/compiler/parser.ts | 4 +- src/compiler/scanner.ts | 2 +- src/compiler/types.ts | 20 +- src/compiler/utilities.ts | 2 + src/compiler/utilitiesPublic.ts | 7 + src/services/completions.ts | 14 +- src/services/inlayHints.ts | 2 +- src/services/jsDoc.ts | 1 + src/services/suggestionDiagnostics.ts | 4 + src/services/symbolDisplay.ts | 2 +- src/services/types.ts | 1 + src/services/utilities.ts | 6 + tests/baselines/reference/api/typescript.d.ts | 75 +++--- ...docParameterTagSnippetCompletion1.baseline | 238 ++++++++++++++++++ ...docParameterTagSnippetCompletion2.baseline | 70 ++++++ ...docParameterTagSnippetCompletion3.baseline | 84 +++++++ tests/cases/fourslash/fourslash.ts | 3 +- .../jsdocExperimental_suggestion19.ts | 18 ++ 22 files changed, 655 insertions(+), 45 deletions(-) create mode 100644 tests/cases/fourslash/jsdocExperimental_suggestion19.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 91bbf4d29d3f0..5a78ca5bb8f96 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1130,6 +1130,7 @@ import { WideningContext, WithStatement, YieldExpression, + getJSDocExperimentalTag, } from "./_namespaces/ts.js"; import * as moduleSpecifiers from "./_namespaces/ts.moduleSpecifiers.js"; import * as performance from "./_namespaces/ts.performance.js"; @@ -2554,6 +2555,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return diagnostic; } + function addExperimentalSuggestionWorker(declarations: Node | Node[], diagnostic: DiagnosticWithLocation) { + const experimentalTag = Array.isArray(declarations) ? forEach(declarations, getJSDocExperimentalTag) : getJSDocDeprecatedTag(declarations); + if (experimentalTag) { + addRelatedInfo( + diagnostic, + createDiagnosticForNode(experimentalTag, Diagnostics.The_declaration_was_marked_as_experimental_here), + ); + } + // We call `addRelatedInfo()` before adding the diagnostic to prevent duplicates. + suggestionDiagnostics.add(diagnostic); + return diagnostic; + } + + + function isDeprecatedSymbol(symbol: Symbol) { const parentSymbol = getParentOfSymbol(symbol); if (parentSymbol && length(symbol.declarations) > 1) { @@ -2563,15 +2579,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { || length(symbol.declarations) && every(symbol.declarations, isDeprecatedDeclaration); } + function isExperimentalSymbol(symbol: Symbol) { + const parentSymbol = getParentOfSymbol(symbol); + if (parentSymbol && length(symbol.declarations) > 1) { + return parentSymbol.flags & SymbolFlags.Interface ? some(symbol.declarations, isExperimentalDeclaration) : every(symbol.declarations, isExperimentalDeclaration); + } + return !!symbol.valueDeclaration && isExperimentalDeclaration(symbol.valueDeclaration) + || length(symbol.declarations) && every(symbol.declarations, isExperimentalDeclaration); + } + function isDeprecatedDeclaration(declaration: Declaration) { return !!(getCombinedNodeFlagsCached(declaration) & NodeFlags.Deprecated); } + function isExperimentalDeclaration(declaration: Declaration) { + return !!(getCombinedNodeFlagsCached(declaration) & NodeFlags.Experimental); + } + function addDeprecatedSuggestion(location: Node, declarations: Node[], deprecatedEntity: string) { const diagnostic = createDiagnosticForNode(location, Diagnostics._0_is_deprecated, deprecatedEntity); return addDeprecatedSuggestionWorker(declarations, diagnostic); } + function addExperimentalSuggestion(location: Node, declarations: Node[], experimentalEntity: string) { + const diagnostic = createDiagnosticForNode(location, Diagnostics._0_is_experimental, experimentalEntity); + return addExperimentalSuggestionWorker(declarations, diagnostic); + } + function addDeprecatedSuggestionWithSignature(location: Node, declaration: Node, deprecatedEntity: string | undefined, signatureString: string) { const diagnostic = deprecatedEntity ? createDiagnosticForNode(location, Diagnostics.The_signature_0_of_1_is_deprecated, signatureString, deprecatedEntity) @@ -2579,6 +2613,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return addDeprecatedSuggestionWorker(declaration, diagnostic); } + function addExperimentalSuggestionWithSignature(location: Node, declaration: Node, experimentalEntity: string | undefined, signatureString: string) { + const diagnostic = experimentalEntity + ? createDiagnosticForNode(location, Diagnostics.The_signature_0_of_1_is_experimental, signatureString, experimentalEntity) + : createDiagnosticForNode(location, Diagnostics._0_is_experimental, signatureString); + return addExperimentalSuggestionWorker(declaration, diagnostic); + } + function createSymbol(flags: SymbolFlags, name: __String, checkFlags?: CheckFlags) { symbolCount++; const symbol = new Symbol(flags | SymbolFlags.Transient, name) as TransientSymbol; @@ -18539,6 +18580,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const deprecatedNode = accessExpression?.argumentExpression ?? (isIndexedAccessTypeNode(accessNode) ? accessNode.indexType : accessNode); addDeprecatedSuggestion(deprecatedNode, prop.declarations, propName as string); } + if (accessFlags & AccessFlags.ReportExperimental && accessNode && prop.declarations && isExperimentalSymbol(prop) && isUncalledFunctionReference(accessNode, prop)) { + const experimentalNode = accessExpression?.argumentExpression ?? (isIndexedAccessTypeNode(accessNode) ? accessNode.indexType : accessNode); + addExperimentalSuggestion(experimentalNode, prop.declarations, propName as string); + } if (accessExpression) { markPropertyAsReferenced(prop, accessExpression, isSelfTypeAccess(accessExpression.expression, objectType.symbol)); if (isAssignmentToReadonlyEntity(accessExpression, prop, getAssignmentTargetKind(accessExpression))) { @@ -19006,7 +19051,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { ? getIntersectionType(propTypes, IntersectionFlags.None, aliasSymbol, aliasTypeArguments) : getUnionType(propTypes, UnionReduction.Literal, aliasSymbol, aliasTypeArguments); } - return getPropertyTypeForIndexType(objectType, apparentObjectType, indexType, indexType, accessNode, accessFlags | AccessFlags.CacheSymbol | AccessFlags.ReportDeprecated); + return getPropertyTypeForIndexType(objectType, apparentObjectType, indexType, indexType, accessNode, accessFlags | AccessFlags.CacheSymbol | AccessFlags.ReportDeprecated | AccessFlags.ReportExperimental); } function getTypeFromIndexedAccessTypeNode(node: IndexedAccessTypeNode) { @@ -30235,10 +30280,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const localOrExportSymbol = getExportSymbolOfValueSymbolIfExported(symbol); - const targetSymbol = resolveAliasWithDeprecationCheck(localOrExportSymbol, node); + const targetSymbol = resolveAliasWithDeprecationAndExperimentalCheck(localOrExportSymbol, node); if (isDeprecatedSymbol(targetSymbol) && isUncalledFunctionReference(node, targetSymbol) && targetSymbol.declarations) { addDeprecatedSuggestion(node, targetSymbol.declarations, node.escapedText as string); } + if (isExperimentalSymbol(targetSymbol) && isUncalledFunctionReference(node, targetSymbol) && targetSymbol.declarations) { + addExperimentalSuggestion(node, targetSymbol.declarations, node.escapedText as string); + } const declaration = localOrExportSymbol.valueDeclaration; if (declaration && localOrExportSymbol.flags & SymbolFlags.Class) { @@ -32997,6 +33045,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (prop && prop.declarations && isDeprecatedSymbol(prop) && isIdentifier(attributeDecl.name)) { addDeprecatedSuggestion(attributeDecl.name, prop.declarations, attributeDecl.name.escapedText as string); } + if (prop && prop.declarations && isExperimentalSymbol(prop) && isIdentifier(attributeDecl.name)) { + addExperimentalSuggestion(attributeDecl.name, prop.declarations, attributeDecl.name.escapedText as string); + } } if (contextualType && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(attributeDecl)) { const inferenceContext = getInferenceContext(attributes); @@ -33484,6 +33535,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const sig = getResolvedSignature(node); checkDeprecatedSignature(sig, node); + checkExperimentalSignature(sig, node) if (isNodeOpeningLikeElement) { const jsxOpeningLikeNode = node; @@ -34114,12 +34166,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (indexInfo.declaration && isDeprecatedDeclaration(indexInfo.declaration)) { addDeprecatedSuggestion(right, [indexInfo.declaration], right.escapedText as string); } + if (indexInfo.declaration && isExperimentalDeclaration(indexInfo.declaration)) { + addExperimentalSuggestion(right, [indexInfo.declaration], right.escapedText as string); + } } else { - const targetPropSymbol = resolveAliasWithDeprecationCheck(prop, right); + const targetPropSymbol = resolveAliasWithDeprecationAndExperimentalCheck(prop, right); if (isDeprecatedSymbol(targetPropSymbol) && isUncalledFunctionReference(node, targetPropSymbol) && targetPropSymbol.declarations) { addDeprecatedSuggestion(right, targetPropSymbol.declarations, right.escapedText as string); } + if (isExperimentalSymbol(targetPropSymbol) && isUncalledFunctionReference(node, targetPropSymbol) && targetPropSymbol.declarations) { + addExperimentalSuggestion(right, targetPropSymbol.declarations, right.escapedText as string); + } checkPropertyNotUsedBeforeDeclaration(prop, node, right); markPropertyAsReferenced(prop, node, isSelfTypeAccess(left, parentSymbol)); getNodeLinks(node).resolvedSymbol = prop; @@ -36952,6 +37010,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } checkDeprecatedSignature(signature, node); + checkExperimentalSignature(signature, node); if (node.expression.kind === SyntaxKind.SuperKeyword) { return voidType; @@ -37022,6 +37081,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } + function checkExperimentalSignature(signature: Signature, node: CallLikeExpression) { + if (signature.flags & SignatureFlags.IsSignatureCandidateForOverloadFailure) return; + if (signature.declaration && signature.declaration.flags & NodeFlags.Experimental) { + const suggestionNode = getExperimentalSuggestionNode(node); + const name = tryGetPropertyAccessOrIdentifierToString(getInvokedExpression(node)); + addExperimentalSuggestionWithSignature(suggestionNode, signature.declaration, name, signatureToString(signature)); + } + } + function getDeprecatedSuggestionNode(node: Node): Node { node = skipParentheses(node); switch (node.kind) { @@ -37046,6 +37114,30 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } } + function getExperimentalSuggestionNode(node: Node): Node { + node = skipParentheses(node); + switch (node.kind) { + case SyntaxKind.CallExpression: + case SyntaxKind.Decorator: + case SyntaxKind.NewExpression: + return getExperimentalSuggestionNode((node as Decorator | CallExpression | NewExpression).expression); + case SyntaxKind.TaggedTemplateExpression: + return getExperimentalSuggestionNode((node as TaggedTemplateExpression).tag); + case SyntaxKind.JsxOpeningElement: + case SyntaxKind.JsxSelfClosingElement: + return getExperimentalSuggestionNode((node as JsxOpeningLikeElement).tagName); + case SyntaxKind.ElementAccessExpression: + return (node as ElementAccessExpression).argumentExpression; + case SyntaxKind.PropertyAccessExpression: + return (node as PropertyAccessExpression).name; + case SyntaxKind.TypeReference: + const typeReference = node as TypeReferenceNode; + return isQualifiedName(typeReference.typeName) ? typeReference.typeName.right : typeReference; + default: + return node; + } + } + function isSymbolOrSymbolForCall(node: Node) { if (!isCallExpression(node)) return false; let left = node.expression; @@ -37187,6 +37279,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } const signature = getResolvedSignature(node); checkDeprecatedSignature(signature, node); + checkExperimentalSignature(signature, node); return getReturnTypeOfSignature(signature); } @@ -41845,6 +41938,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { symbol.escapedName as string, ); } + if (some(symbol.declarations, d => isTypeDeclaration(d) && !!(d.flags & NodeFlags.Experimental))) { + addExperimentalSuggestion( + getExperimentalSuggestionNode(node), + symbol.declarations!, + symbol.escapedName as string, + ); + } } } } @@ -43016,6 +43116,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const signature = getResolvedSignature(node); checkDeprecatedSignature(signature, node); + checkExperimentalSignature(signature, node); const returnType = getReturnTypeOfSignature(signature); if (returnType.flags & TypeFlags.Any) { return; @@ -47495,16 +47596,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } if (isImportSpecifier(node)) { - const targetSymbol = resolveAliasWithDeprecationCheck(symbol, node); + const targetSymbol = resolveAliasWithDeprecationAndExperimentalCheck(symbol, node); if (isDeprecatedSymbol(targetSymbol) && targetSymbol.declarations) { addDeprecatedSuggestion(node, targetSymbol.declarations, targetSymbol.escapedName as string); } + if (isExperimentalSymbol(targetSymbol) && targetSymbol.declarations){ + addExperimentalSuggestion(node, targetSymbol.declarations, targetSymbol.escapedName as string); + } } } } - function resolveAliasWithDeprecationCheck(symbol: Symbol, location: Node) { - if (!(symbol.flags & SymbolFlags.Alias) || isDeprecatedSymbol(symbol) || !getDeclarationOfAliasSymbol(symbol)) { + function resolveAliasWithDeprecationAndExperimentalCheck(symbol: Symbol, location: Node) { + if (!(symbol.flags & SymbolFlags.Alias) || isDeprecatedSymbol(symbol) || isExperimentalSymbol(symbol) || !getDeclarationOfAliasSymbol(symbol)) { return symbol; } @@ -47520,6 +47624,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { addDeprecatedSuggestion(location, target.declarations, target.escapedName as string); break; } + else if (isExperimentalSymbol(target)){ + addExperimentalSuggestion(location, target.declarations, target.escapedName as string); + break; + } else { if (symbol === targetSymbol) break; symbol = target; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 7f686076f1824..84aed4ded1869 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -8425,5 +8425,19 @@ "String literal import and export names are not supported when the '--module' flag is set to 'es2015' or 'es2020'.": { "category": "Error", "code": 18057 + }, + "'{0}' is experimental.": { + "category": "Suggestion", + "code": 18058, + "reportsExperimental": true + }, + "The declaration was marked as experimental here.": { + "category": "Message", + "code": 18059 + }, + "The signature '{0}' of '{1}' is experimental.": { + "category": "Suggestion", + "code": 18060, + "reportsExperimental": true } } diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index fbc97d9aa4d9c..8494c4d20da86 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -224,6 +224,7 @@ import { JSDocComment, JSDocDeprecatedTag, JSDocEnumTag, + JSDocExperimentalTag, JSDocFunctionType, JSDocImplementsTag, JSDocImportTag, @@ -939,6 +940,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode get updateJSDocDeprecatedTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocDeprecatedTag); }, + get createJSDocExperimentalTag() { + return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocExperimentalTag); + }, + get updateJSDocExperimentalTag() { + return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocExperimentalTag); + }, get createJSDocThrowsTag() { return getJSDocTypeLikeTagCreateFunction(SyntaxKind.JSDocThrowsTag); }, diff --git a/src/compiler/factory/nodeTests.ts b/src/compiler/factory/nodeTests.ts index 8aa4bb02e83d2..64facda9c059a 100644 --- a/src/compiler/factory/nodeTests.ts +++ b/src/compiler/factory/nodeTests.ts @@ -89,6 +89,7 @@ import { JSDocClassTag, JSDocDeprecatedTag, JSDocEnumTag, + JSDocExperimentalTag, JSDocFunctionType, JSDocImplementsTag, JSDocImportTag, @@ -1137,6 +1138,11 @@ export function isJSDocDeprecatedTag(node: Node): node is JSDocDeprecatedTag { return node.kind === SyntaxKind.JSDocDeprecatedTag; } +export function isJsDOcExperimentalTag(node: Node): node is JSDocExperimentalTag{ + return node.kind === SyntaxKind.JSDocExperimentalTag; +} + + export function isJSDocSeeTag(node: Node): node is JSDocSeeTag { return node.kind === SyntaxKind.JSDocSeeTag; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index a842766f058ac..0dc9b7ccb34fa 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -175,6 +175,7 @@ import { JSDocComment, JSDocDeprecatedTag, JSDocEnumTag, + JSDocExperimentalTag, JSDocFunctionType, JSDocImplementsTag, JSDocImportTag, @@ -1129,6 +1130,7 @@ const forEachChildTable: ForEachChildTable = { [SyntaxKind.JSDocProtectedTag]: forEachChildInJSDocTag, [SyntaxKind.JSDocReadonlyTag]: forEachChildInJSDocTag, [SyntaxKind.JSDocDeprecatedTag]: forEachChildInJSDocTag, + [SyntaxKind.JSDocExperimentalTag]: forEachChildInJSDocTag, [SyntaxKind.JSDocOverrideTag]: forEachChildInJSDocTag, [SyntaxKind.JSDocImportTag]: forEachChildInJSDocImportTag, [SyntaxKind.PartiallyEmittedExpression]: forEachChildInPartiallyEmittedExpression, @@ -1215,7 +1217,7 @@ function forEachChildInJSDocLinkCodeOrPlain(node: JSDocLink | JSDocLinkCode | return visitNode(cbNode, node.name); } -function forEachChildInJSDocTag(node: JSDocUnknownTag | JSDocClassTag | JSDocPublicTag | JSDocPrivateTag | JSDocProtectedTag | JSDocReadonlyTag | JSDocDeprecatedTag | JSDocOverrideTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { +function forEachChildInJSDocTag(node: JSDocUnknownTag | JSDocClassTag | JSDocPublicTag | JSDocPrivateTag | JSDocProtectedTag | JSDocReadonlyTag | JSDocDeprecatedTag | JSDocOverrideTag | JSDocExperimentalTag, cbNode: (node: Node) => T | undefined, cbNodes?: (nodes: NodeArray) => T | undefined): T | undefined { return visitNode(cbNode, node.tagName) || (typeof node.comment === "string" ? undefined : visitNodes(cbNode, cbNodes, node.comment)); } diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 50e827c17bd24..1b44af40f8395 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -4081,7 +4081,7 @@ const nonBinaryUnicodeProperties = new Map(Object.entries({ // Table 67: Binary Unicode property aliases and their canonical property names // https://tc39.es/ecma262/#table-binary-unicode-properties // dprint-ignore -const binaryUnicodeProperties = new Set(["ASCII", "ASCII_Hex_Digit", "AHex", "Alphabetic", "Alpha", "Any", "Assigned", "Bidi_Control", "Bidi_C", "Bidi_Mirrored", "Bidi_M", "Case_Ignorable", "CI", "Cased", "Changes_When_Casefolded", "CWCF", "Changes_When_Casemapped", "CWCM", "Changes_When_Lowercased", "CWL", "Changes_When_NFKC_Casefolded", "CWKCF", "Changes_When_Titlecased", "CWT", "Changes_When_Uppercased", "CWU", "Dash", "Default_Ignorable_Code_Point", "DI", "Deprecated", "Dep", "Diacritic", "Dia", "Emoji", "Emoji_Component", "EComp", "Emoji_Modifier", "EMod", "Emoji_Modifier_Base", "EBase", "Emoji_Presentation", "EPres", "Extended_Pictographic", "ExtPict", "Extender", "Ext", "Grapheme_Base", "Gr_Base", "Grapheme_Extend", "Gr_Ext", "Hex_Digit", "Hex", "IDS_Binary_Operator", "IDSB", "IDS_Trinary_Operator", "IDST", "ID_Continue", "IDC", "ID_Start", "IDS", "Ideographic", "Ideo", "Join_Control", "Join_C", "Logical_Order_Exception", "LOE", "Lowercase", "Lower", "Math", "Noncharacter_Code_Point", "NChar", "Pattern_Syntax", "Pat_Syn", "Pattern_White_Space", "Pat_WS", "Quotation_Mark", "QMark", "Radical", "Regional_Indicator", "RI", "Sentence_Terminal", "STerm", "Soft_Dotted", "SD", "Terminal_Punctuation", "Term", "Unified_Ideograph", "UIdeo", "Uppercase", "Upper", "Variation_Selector", "VS", "White_Space", "space", "XID_Continue", "XIDC", "XID_Start", "XIDS"]); +const binaryUnicodeProperties = new Set(["ASCII", "ASCII_Hex_Digit", "AHex", "Alphabetic", "Alpha", "Any", "Assigned", "Bidi_Control", "Bidi_C", "Bidi_Mirrored", "Bidi_M", "Case_Ignorable", "CI", "Cased", "Changes_When_Casefolded", "CWCF", "Changes_When_Casemapped", "CWCM", "Changes_When_Lowercased", "CWL", "Changes_When_NFKC_Casefolded", "CWKCF", "Changes_When_Titlecased", "CWT", "Changes_When_Uppercased", "CWU", "Dash", "Default_Ignorable_Code_Point", "DI", "Deprecated", "Experimental", "Dep", "Diacritic", "Dia", "Emoji", "Emoji_Component", "EComp", "Emoji_Modifier", "EMod", "Emoji_Modifier_Base", "EBase", "Emoji_Presentation", "EPres", "Extended_Pictographic", "ExtPict", "Extender", "Ext", "Grapheme_Base", "Gr_Base", "Grapheme_Extend", "Gr_Ext", "Hex_Digit", "Hex", "IDS_Binary_Operator", "IDSB", "IDS_Trinary_Operator", "IDST", "ID_Continue", "IDC", "ID_Start", "IDS", "Ideographic", "Ideo", "Join_Control", "Join_C", "Logical_Order_Exception", "LOE", "Lowercase", "Lower", "Math", "Noncharacter_Code_Point", "NChar", "Pattern_Syntax", "Pat_Syn", "Pattern_White_Space", "Pat_WS", "Quotation_Mark", "QMark", "Radical", "Regional_Indicator", "RI", "Sentence_Terminal", "STerm", "Soft_Dotted", "SD", "Terminal_Punctuation", "Term", "Unified_Ideograph", "UIdeo", "Uppercase", "Upper", "Variation_Selector", "VS", "White_Space", "space", "XID_Continue", "XIDC", "XID_Start", "XIDS"]); // Table 68: Binary Unicode properties of strings // https://tc39.es/ecma262/#table-binary-unicode-properties-of-strings diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 374451a2aadb1..59b5c2331ae12 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -419,6 +419,7 @@ export const enum SyntaxKind { JSDocImplementsTag, JSDocAuthorTag, JSDocDeprecatedTag, + JSDocExperimentalTag, JSDocClassTag, JSDocPublicTag, JSDocPrivateTag, @@ -820,6 +821,7 @@ export const enum NodeFlags { JsonFile = 1 << 27, // If node was parsed in a Json /** @internal */ TypeCached = 1 << 28, // If a type was cached for node at any point /** @internal */ Deprecated = 1 << 29, // If has '@deprecated' JSDoc tag + /** @internal */ Experimental = 1 << 30, // If has '@experimental' JSDoc tag BlockScoped = Let | Const | Using, Constant = Const | Using, @@ -869,6 +871,7 @@ export const enum ModifierFlags { // JSDoc-only modifiers Deprecated = 1 << 16, // Deprecated tag. + Experimental = 1 << 17, // Experimental tag. // Cache-only JSDoc-modifiers. Should match order of Syntactic/JSDoc modifiers, above. /** @internal */ JSDocPublic = 1 << 23, // if this value changes, `selectEffectiveModifierFlags` must change accordingly @@ -881,7 +884,7 @@ export const enum ModifierFlags { /** @internal */ SyntacticOnlyModifiers = Export | Ambient | Abstract | Static | Accessor | Async | Default | Const | In | Out | Decorator, /** @internal */ SyntacticModifiers = SyntacticOrJSDocModifiers | SyntacticOnlyModifiers, /** @internal */ JSDocCacheOnlyModifiers = JSDocPublic | JSDocPrivate | JSDocProtected | JSDocReadonly | JSDocOverride, - /** @internal */ JSDocOnlyModifiers = Deprecated, + /** @internal */ JSDocOnlyModifiers = Deprecated | Experimental, /** @internal */ NonCacheOnlyModifiers = SyntacticOrJSDocModifiers | SyntacticOnlyModifiers | JSDocOnlyModifiers, HasComputedJSDocModifiers = 1 << 28, // Indicates the computed modifier flags include modifiers from JSDoc. @@ -894,7 +897,7 @@ export const enum ModifierFlags { TypeScriptModifier = Ambient | Public | Private | Protected | Readonly | Abstract | Const | Override | In | Out, ExportDefault = Export | Default, - All = Export | Ambient | Public | Private | Protected | Static | Readonly | Abstract | Accessor | Async | Default | Const | Deprecated | Override | In | Out | Decorator, + All = Export | Ambient | Public | Private | Protected | Static | Readonly | Abstract | Accessor | Async | Default | Const | Deprecated | Experimental | Override | In | Out | Decorator, Modifier = All & ~Decorator, } @@ -1047,6 +1050,7 @@ export type ForEachChildNodes = | JSDocProtectedTag | JSDocReadonlyTag | JSDocDeprecatedTag + | JSDocExperimentalTag | JSDocThrowsTag | JSDocOverrideTag | JSDocSatisfiesTag @@ -3995,6 +3999,10 @@ export interface JSDocDeprecatedTag extends JSDocTag { kind: SyntaxKind.JSDocDeprecatedTag; } +export interface JSDocExperimentalTag extends JSDocTag { + kind: SyntaxKind.JSDocExperimentalTag; +} + export interface JSDocClassTag extends JSDocTag { readonly kind: SyntaxKind.JSDocClassTag; } @@ -6826,6 +6834,7 @@ export const enum AccessFlags { ReportDeprecated = 1 << 6, SuppressNoImplicitAnyError = 1 << 7, Contextual = 1 << 8, + ReportExperimental = 1 << 9, Persistent = IncludeUndefined, } @@ -7154,6 +7163,7 @@ export interface DiagnosticMessage { message: string; reportsUnnecessary?: {}; reportsDeprecated?: {}; + reportsExperimental?: {}, /** @internal */ elidedInCompatabilityPyramid?: boolean; } @@ -7193,6 +7203,7 @@ export interface Diagnostic extends DiagnosticRelatedInformation { reportsUnnecessary?: {}; reportsDeprecated?: {}; + reportsExperimental?: {}; source?: string; relatedInformation?: DiagnosticRelatedInformation[]; /** @internal */ skippedOn?: keyof CompilerOptions; @@ -9117,8 +9128,13 @@ export interface NodeFactory { updateJSDocReadonlyTag(node: JSDocReadonlyTag, tagName: Identifier | undefined, comment: string | NodeArray | undefined): JSDocReadonlyTag; createJSDocUnknownTag(tagName: Identifier, comment?: string | NodeArray): JSDocUnknownTag; updateJSDocUnknownTag(node: JSDocUnknownTag, tagName: Identifier, comment: string | NodeArray | undefined): JSDocUnknownTag; + createJSDocDeprecatedTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocDeprecatedTag; updateJSDocDeprecatedTag(node: JSDocDeprecatedTag, tagName: Identifier | undefined, comment?: string | NodeArray): JSDocDeprecatedTag; + + createJSDocExperimentalTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocExperimentalTag; + updateJSDocExperimentalTag(node: JSDocExperimentalTag, tagName: Identifier | undefined, comment?: string | NodeArray): JSDocExperimentalTag; + createJSDocOverrideTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocOverrideTag; updateJSDocOverrideTag(node: JSDocOverrideTag, tagName: Identifier | undefined, comment?: string | NodeArray): JSDocOverrideTag; createJSDocThrowsTag(tagName: Identifier, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray): JSDocThrowsTag; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index fc55fb1411772..b4d43c21ff468 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -8599,6 +8599,8 @@ export function formatMessage(message: DiagnosticMessage, ...args: DiagnosticArg /** @internal */ export function createCompilerDiagnostic(message: DiagnosticMessage, ...args: DiagnosticArguments): Diagnostic { let text = getLocaleSpecificMessage(message); + //@ts-ignore + console.log(text) if (some(args)) { text = formatStringFromArgs(text, args); diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index 02e22b94c895e..2d54075bbd46c 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -139,6 +139,7 @@ import { isJSDocClassTag, isJSDocDeprecatedTag, isJSDocEnumTag, + isJsDOcExperimentalTag, isJSDocFunctionType, isJSDocImplementsTag, isJSDocOverloadTag, @@ -183,6 +184,7 @@ import { JSDocContainer, JSDocDeprecatedTag, JSDocEnumTag, + JSDocExperimentalTag, JSDocImplementsTag, JSDocLink, JSDocLinkCode, @@ -1163,6 +1165,11 @@ export function getJSDocDeprecatedTag(node: Node): JSDocDeprecatedTag | undefine return getFirstJSDocTag(node, isJSDocDeprecatedTag); } +/** Gets the JSDoc experimental tag for the node if present */ +export function getJSDocExperimentalTag(node: Node): JSDocExperimentalTag | undefined { + return getFirstJSDocTag(node, isJsDOcExperimentalTag); +} + /** @internal */ export function getJSDocDeprecatedTagNoCache(node: Node): JSDocDeprecatedTag | undefined { return getFirstJSDocTag(node, isJSDocDeprecatedTag, /*noCache*/ true); diff --git a/src/services/completions.ts b/src/services/completions.ts index 3291902986fa0..05bd0275f32bb 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -155,6 +155,7 @@ import { isDeclarationName, isDecorator, isDeprecatedDeclaration, + isExperimentalDeclaration, isEntityName, isEnumMember, isEqualityOperatorKind, @@ -424,6 +425,10 @@ export const SortText = { return "z" + sortText as SortText; }, + Experimental(sortText: SortText): SortText { + return "z" + sortText as SortText; + }, + ObjectLiteralProperty(presetSortText: SortText, symbolDisplayName: string): SortText { return `${presetSortText}\0${symbolDisplayName}\0` as SortText; }, @@ -2689,7 +2694,9 @@ export function getCompletionEntriesFromSymbols( const { name, needsConvertPropertyAccess } = info; const originalSortText = symbolToSortTextMap?.[getSymbolId(symbol)] ?? SortText.LocationPriority; - const sortText = isDeprecated(symbol, typeChecker) ? SortText.Deprecated(originalSortText) : originalSortText; + const _isDeprecated = isDeprecated(symbol, typeChecker); + let sortText = _isDeprecated ? SortText.Deprecated(originalSortText) : originalSortText; + if (!_isDeprecated) sortText = isExperimental(symbol, typeChecker)? SortText.Experimental(originalSortText) : originalSortText; const entry = createCompletionEntry( symbol, sortText, @@ -6068,6 +6075,11 @@ function isDeprecated(symbol: Symbol, checker: TypeChecker) { return !!length(declarations) && every(declarations, isDeprecatedDeclaration); } +function isExperimental(symbol: Symbol, checker: TypeChecker) { + const declarations = skipAlias(symbol, checker).declarations; + return !!length(declarations) && every(declarations, isExperimentalDeclaration); +} + /** * True if the first character of `lowercaseCharacters` is the first character * of some "word" in `identiferString` (where the string is split into "words" diff --git a/src/services/inlayHints.ts b/src/services/inlayHints.ts index a3e54cf237896..8e62c816cfe2b 100644 --- a/src/services/inlayHints.ts +++ b/src/services/inlayHints.ts @@ -229,7 +229,7 @@ export function provideInlayHints(context: InlayHintsContext): InlayHint[] { function addTypeHints(hintText: string | InlayHintDisplayPart[], position: number) { result.push({ - text: typeof hintText === "string" ? `: ${hintText}` : "", + text: typeof hintText === "string" ? ": " + hintText : "", displayParts: typeof hintText === "string" ? undefined : [{ text: ": " }, ...hintText], position, kind: InlayHintKind.Type, diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 0f8cb859d6822..172106de90209 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -112,6 +112,7 @@ const jsDocTagNames = [ "copyright", "default", "deprecated", + "experimental", "description", "emits", "enum", diff --git a/src/services/suggestionDiagnostics.ts b/src/services/suggestionDiagnostics.ts index 3c4cf5c39b976..5ae3934594c1f 100644 --- a/src/services/suggestionDiagnostics.ts +++ b/src/services/suggestionDiagnostics.ts @@ -90,6 +90,7 @@ export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Pr const module = program.getResolvedModuleFromModuleSpecifier(moduleSpecifier, sourceFile)?.resolvedModule; const resolvedFile = module && program.getSourceFile(module.resolvedFileName); if (resolvedFile && resolvedFile.externalModuleIndicator && resolvedFile.externalModuleIndicator !== true && isExportAssignment(resolvedFile.externalModuleIndicator) && resolvedFile.externalModuleIndicator.isExportEquals) { + diags.push(createDiagnosticForNode(name, Diagnostics.Import_may_be_converted_to_a_default_import)); } } @@ -98,9 +99,11 @@ export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Pr addRange(diags, sourceFile.bindSuggestionDiagnostics); addRange(diags, program.getSuggestionDiagnostics(sourceFile, cancellationToken)); diags.sort((d1, d2) => d1.start - d2.start); + return diags; function check(node: Node) { + if (isJsFile) { if (canBeConvertedToClass(node, checker)) { diags.push(createDiagnosticForNode(isVariableDeclaration(node.parent) ? node.parent.name : node, Diagnostics.This_constructor_function_may_be_converted_to_a_class_declaration)); @@ -134,6 +137,7 @@ export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Pr } node.forEachChild(check); } + } // convertToEsModule only works on top-level, so don't trigger it if commonjs code only appears in nested scopes. diff --git a/src/services/symbolDisplay.ts b/src/services/symbolDisplay.ts index 6c49848435e70..9e2e0d77e0c6e 100644 --- a/src/services/symbolDisplay.ts +++ b/src/services/symbolDisplay.ts @@ -851,7 +851,7 @@ function getSymbolDisplayPartsDocumentationAndSymbolKindWorker(typeChecker: Type if (allSignatures.length > 1 && documentation.length === 0 && tags.length === 0) { documentation = allSignatures[0].getDocumentationComment(typeChecker); - tags = allSignatures[0].getJsDocTags().filter(tag => tag.name !== "deprecated"); // should only include @deprecated JSDoc tag on the first overload (#49368) + tags = allSignatures[0].getJsDocTags().filter(tag => !(["deprecated", "experimental"].includes(tag.name))); // should only include @deprecated & @experimental JSDoc tags on the first overload (#49368) } } diff --git a/src/services/types.ts b/src/services/types.ts index 69fdb42cf6926..d5166dd2ce21b 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -1825,6 +1825,7 @@ export const enum ScriptElementKindModifier { optionalModifier = "optional", deprecatedModifier = "deprecated", + experimentalModifier = "experimental", dtsModifier = ".d.ts", tsModifier = ".ts", diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 356c2878c90b8..1d941a91b20f5 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -2175,6 +2175,7 @@ export function getNodeModifiers(node: Node, excludeFlags: ModifierFlags = Modif if (flags & ModifierFlags.Abstract) result.push(ScriptElementKindModifier.abstractModifier); if (flags & ModifierFlags.Export) result.push(ScriptElementKindModifier.exportedModifier); if (flags & ModifierFlags.Deprecated) result.push(ScriptElementKindModifier.deprecatedModifier); + if (flags & ModifierFlags.Experimental) result.push(ScriptElementKindModifier.experimentalModifier); if (node.flags & NodeFlags.Ambient) result.push(ScriptElementKindModifier.ambientModifier); if (node.kind === SyntaxKind.ExportAssignment) result.push(ScriptElementKindModifier.exportedModifier); @@ -4123,6 +4124,11 @@ export function isDeprecatedDeclaration(decl: Declaration): boolean { return !!(getCombinedNodeFlagsAlwaysIncludeJSDoc(decl) & ModifierFlags.Deprecated); } +/** @internal */ +export function isExperimentalDeclaration(decl: Declaration): boolean { + return !!(getCombinedNodeFlagsAlwaysIncludeJSDoc(decl) & ModifierFlags.Experimental); +} + /** @internal */ export function shouldUseUriStyleNodeCoreModules(file: SourceFile | FutureSourceFile, program: Program): boolean | undefined { let decisionFromFile; diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index 0ed1d1e839fcd..f8dab87affd37 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -4010,33 +4010,34 @@ declare namespace ts { JSDocImplementsTag = 329, JSDocAuthorTag = 330, JSDocDeprecatedTag = 331, - JSDocClassTag = 332, - JSDocPublicTag = 333, - JSDocPrivateTag = 334, - JSDocProtectedTag = 335, - JSDocReadonlyTag = 336, - JSDocOverrideTag = 337, - JSDocCallbackTag = 338, - JSDocOverloadTag = 339, - JSDocEnumTag = 340, - JSDocParameterTag = 341, - JSDocReturnTag = 342, - JSDocThisTag = 343, - JSDocTypeTag = 344, - JSDocTemplateTag = 345, - JSDocTypedefTag = 346, - JSDocSeeTag = 347, - JSDocPropertyTag = 348, - JSDocThrowsTag = 349, - JSDocSatisfiesTag = 350, - JSDocImportTag = 351, - SyntaxList = 352, - NotEmittedStatement = 353, - NotEmittedTypeElement = 354, - PartiallyEmittedExpression = 355, - CommaListExpression = 356, - SyntheticReferenceExpression = 357, - Count = 358, + JSDocExperimentalTag = 332, + JSDocClassTag = 333, + JSDocPublicTag = 334, + JSDocPrivateTag = 335, + JSDocProtectedTag = 336, + JSDocReadonlyTag = 337, + JSDocOverrideTag = 338, + JSDocCallbackTag = 339, + JSDocOverloadTag = 340, + JSDocEnumTag = 341, + JSDocParameterTag = 342, + JSDocReturnTag = 343, + JSDocThisTag = 344, + JSDocTypeTag = 345, + JSDocTemplateTag = 346, + JSDocTypedefTag = 347, + JSDocSeeTag = 348, + JSDocPropertyTag = 349, + JSDocThrowsTag = 350, + JSDocSatisfiesTag = 351, + JSDocImportTag = 352, + SyntaxList = 353, + NotEmittedStatement = 354, + NotEmittedTypeElement = 355, + PartiallyEmittedExpression = 356, + CommaListExpression = 357, + SyntheticReferenceExpression = 358, + Count = 359, FirstAssignment = 64, LastAssignment = 79, FirstCompoundAssignment = 65, @@ -4065,9 +4066,9 @@ declare namespace ts { LastStatement = 259, FirstNode = 166, FirstJSDocNode = 309, - LastJSDocNode = 351, + LastJSDocNode = 352, FirstJSDocTagNode = 327, - LastJSDocTagNode = 351, + LastJSDocTagNode = 352, } type TriviaSyntaxKind = SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia | SyntaxKind.NewLineTrivia | SyntaxKind.WhitespaceTrivia | SyntaxKind.ShebangTrivia | SyntaxKind.ConflictMarkerTrivia; type LiteralSyntaxKind = SyntaxKind.NumericLiteral | SyntaxKind.BigIntLiteral | SyntaxKind.StringLiteral | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.RegularExpressionLiteral | SyntaxKind.NoSubstitutionTemplateLiteral; @@ -4276,6 +4277,7 @@ declare namespace ts { Out = 16384, Decorator = 32768, Deprecated = 65536, + Experimental = 131072, HasComputedJSDocModifiers = 268435456, HasComputedFlags = 536870912, AccessibilityModifier = 7, @@ -4283,8 +4285,8 @@ declare namespace ts { NonPublicAccessibilityModifier = 6, TypeScriptModifier = 28895, ExportDefault = 2080, - All = 131071, - Modifier = 98303, + All = 262143, + Modifier = 229375, } enum JsxFlags { None = 0, @@ -5776,6 +5778,9 @@ declare namespace ts { interface JSDocDeprecatedTag extends JSDocTag { kind: SyntaxKind.JSDocDeprecatedTag; } + interface JSDocExperimentalTag extends JSDocTag { + kind: SyntaxKind.JSDocExperimentalTag; + } interface JSDocClassTag extends JSDocTag { readonly kind: SyntaxKind.JSDocClassTag; } @@ -6887,6 +6892,7 @@ declare namespace ts { message: string; reportsUnnecessary?: {}; reportsDeprecated?: {}; + reportsExperimental?: {}; } /** * A linked list of formatted diagnostic messages to be used as part of a multiline message. @@ -6904,6 +6910,7 @@ declare namespace ts { /** May store more in future. For now, this will simply be `true` to indicate when a diagnostic is an unused-identifier diagnostic. */ reportsUnnecessary?: {}; reportsDeprecated?: {}; + reportsExperimental?: {}; source?: string; relatedInformation?: DiagnosticRelatedInformation[]; } @@ -7815,6 +7822,8 @@ declare namespace ts { updateJSDocUnknownTag(node: JSDocUnknownTag, tagName: Identifier, comment: string | NodeArray | undefined): JSDocUnknownTag; createJSDocDeprecatedTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocDeprecatedTag; updateJSDocDeprecatedTag(node: JSDocDeprecatedTag, tagName: Identifier | undefined, comment?: string | NodeArray): JSDocDeprecatedTag; + createJSDocExperimentalTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocExperimentalTag; + updateJSDocExperimentalTag(node: JSDocExperimentalTag, tagName: Identifier | undefined, comment?: string | NodeArray): JSDocExperimentalTag; createJSDocOverrideTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocOverrideTag; updateJSDocOverrideTag(node: JSDocOverrideTag, tagName: Identifier | undefined, comment?: string | NodeArray): JSDocOverrideTag; createJSDocThrowsTag(tagName: Identifier, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray): JSDocThrowsTag; @@ -8670,6 +8679,8 @@ declare namespace ts { function getJSDocOverrideTagNoCache(node: Node): JSDocOverrideTag | undefined; /** Gets the JSDoc deprecated tag for the node if present */ function getJSDocDeprecatedTag(node: Node): JSDocDeprecatedTag | undefined; + /** Gets the JSDoc experimental tag for the node if present */ + function getJSDocExperimentalTag(node: Node): JSDocExperimentalTag | undefined; /** Gets the JSDoc enum tag for the node if present */ function getJSDocEnumTag(node: Node): JSDocEnumTag | undefined; /** Gets the JSDoc this tag for the node if present */ @@ -9116,6 +9127,7 @@ declare namespace ts { function isJSDocOverrideTag(node: Node): node is JSDocOverrideTag; function isJSDocOverloadTag(node: Node): node is JSDocOverloadTag; function isJSDocDeprecatedTag(node: Node): node is JSDocDeprecatedTag; + function isJsDOcExperimentalTag(node: Node): node is JSDocExperimentalTag; function isJSDocSeeTag(node: Node): node is JSDocSeeTag; function isJSDocEnumTag(node: Node): node is JSDocEnumTag; function isJSDocParameterTag(node: Node): node is JSDocParameterTag; @@ -11184,6 +11196,7 @@ declare namespace ts { abstractModifier = "abstract", optionalModifier = "optional", deprecatedModifier = "deprecated", + experimentalModifier = "experimental", dtsModifier = ".d.ts", tsModifier = ".ts", tsxModifier = ".tsx", diff --git a/tests/baselines/reference/jsdocParameterTagSnippetCompletion1.baseline b/tests/baselines/reference/jsdocParameterTagSnippetCompletion1.baseline index 644bd98bd242a..3d21a65f2f315 100644 --- a/tests/baselines/reference/jsdocParameterTagSnippetCompletion1.baseline +++ b/tests/baselines/reference/jsdocParameterTagSnippetCompletion1.baseline @@ -21,6 +21,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -118,6 +119,7 @@ // | @copyright // | @default // | @deprecated +// | @experimental // | @description // | @emits // | @enum @@ -212,6 +214,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -311,6 +314,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -412,6 +416,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -508,6 +513,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -605,6 +611,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -702,6 +709,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -798,6 +806,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -895,6 +904,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -989,6 +999,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -1084,6 +1095,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -1179,6 +1191,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -1273,6 +1286,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -1369,6 +1383,7 @@ // | @copyright // | @default // | @deprecated +// | @experimental // | @description // | @emits // | @enum @@ -1463,6 +1478,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -1559,6 +1575,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -1866,6 +1883,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -3003,6 +3033,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -4140,6 +4183,19 @@ ], "documentation": [] }, + { + "name": "@experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "@experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "@description", "kind": "", @@ -5264,6 +5320,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -6388,6 +6457,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -7512,6 +7594,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -8649,6 +8744,19 @@ ], "documentation": [] }, + { + "name": "@experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "@experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "@description", "kind": "", @@ -9773,6 +9881,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -10897,6 +11018,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -12021,6 +12155,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -13145,6 +13292,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -14269,6 +14429,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -15393,6 +15566,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -16517,6 +16703,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -17654,6 +17853,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -18778,6 +18990,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -19902,6 +20127,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", diff --git a/tests/baselines/reference/jsdocParameterTagSnippetCompletion2.baseline b/tests/baselines/reference/jsdocParameterTagSnippetCompletion2.baseline index 67e028bde039f..66a1c49dfee43 100644 --- a/tests/baselines/reference/jsdocParameterTagSnippetCompletion2.baseline +++ b/tests/baselines/reference/jsdocParameterTagSnippetCompletion2.baseline @@ -21,6 +21,7 @@ // | @copyright // | @default // | @deprecated +// | @experimental // | @description // | @emits // | @enum @@ -115,6 +116,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -214,6 +216,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -307,6 +310,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -401,6 +405,7 @@ // | @copyright // | @default // | @deprecated +// | @experimental // | @description // | @emits // | @enum @@ -706,6 +711,19 @@ ], "documentation": [] }, + { + "name": "@experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "@experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "@description", "kind": "", @@ -1832,6 +1850,19 @@ ], "documentation": [] }, + { + "name": "@experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "@experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "@description", "kind": "", @@ -2958,6 +2989,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -4084,6 +4128,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -5210,6 +5267,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", diff --git a/tests/baselines/reference/jsdocParameterTagSnippetCompletion3.baseline b/tests/baselines/reference/jsdocParameterTagSnippetCompletion3.baseline index 1496e3085daab..1425aeb4b397e 100644 --- a/tests/baselines/reference/jsdocParameterTagSnippetCompletion3.baseline +++ b/tests/baselines/reference/jsdocParameterTagSnippetCompletion3.baseline @@ -21,6 +21,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -113,6 +114,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -206,6 +208,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -302,6 +305,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -398,6 +402,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -492,6 +497,7 @@ // | copyright // | default // | deprecated +// | experimental // | description // | emits // | enum @@ -798,6 +804,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -1922,6 +1941,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -3046,6 +3078,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -4170,6 +4215,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -5294,6 +5352,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", @@ -6418,6 +6489,19 @@ ], "documentation": [] }, + { + "name": "experimental", + "kind": "", + "kindModifiers": "", + "sortText": "11", + "displayParts": [ + { + "text": "experimental", + "kind": "text" + } + ], + "documentation": [] + }, { "name": "description", "kind": "", diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index f4f4b960753f5..4589a13a8a3cb 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -323,7 +323,7 @@ declare namespace FourSlashInterface { * to 'value'. Do not use this function with external modules as it is not supported. */ eval(expr: string, value: any): void; - currentLineContentIs(text: string): void; + curentLineContentIs(text: string): void; currentFileContentIs(text: string): void; formatDocumentChangesNothing(): void; verifyGetEmitOutputForCurrentFile(expected: string): void; @@ -669,6 +669,7 @@ declare namespace FourSlashInterface { code: number; reportsUnnecessary?: true; reportsDeprecated?: true; + reportsExperimental?: true; } interface VerifyDocumentHighlightsOptions { filesToSearch: ReadonlyArray; diff --git a/tests/cases/fourslash/jsdocExperimental_suggestion19.ts b/tests/cases/fourslash/jsdocExperimental_suggestion19.ts new file mode 100644 index 0000000000000..796131cab0e8a --- /dev/null +++ b/tests/cases/fourslash/jsdocExperimental_suggestion19.ts @@ -0,0 +1,18 @@ +/// + +////interface I { +//// /** @experimental */ +//// x: number; +////} +////const foo: I = { x: 1, y: 1 }; +////foo.[|x|]; + +const [range] = test.ranges(); +verify.getSuggestionDiagnostics([ + { + "code": 18058, + "message": "'x' is experimental.", + "range": range, + "reportsExperimental": true + }, +]); From b7eca18ad1152764ad25876b420700dcf3464ac8 Mon Sep 17 00:00:00 2001 From: Triston Armstrong Date: Mon, 14 Oct 2024 14:09:17 -0400 Subject: [PATCH 2/2] get jsdoc experimental tag to actually work --- scripts/processDiagnosticMessages.mjs | 8 +++++--- src/compiler/builder.ts | 3 +++ src/compiler/parser.ts | 9 +++++++++ src/compiler/utilities.ts | 4 ++-- src/harness/client.ts | 1 + src/harness/fourslashImpl.ts | 3 +++ src/harness/fourslashInterfaceImpl.ts | 2 ++ src/server/protocol.ts | 3 +++ src/server/session.ts | 4 ++++ src/testRunner/unittests/tscWatch/incremental.ts | 1 + tests/baselines/reference/api/typescript.d.ts | 2 ++ tests/cases/fourslash/fourslash.ts | 2 +- 12 files changed, 36 insertions(+), 6 deletions(-) diff --git a/scripts/processDiagnosticMessages.mjs b/scripts/processDiagnosticMessages.mjs index 33d373936a4b7..1cc93f43bbac4 100644 --- a/scripts/processDiagnosticMessages.mjs +++ b/scripts/processDiagnosticMessages.mjs @@ -6,6 +6,7 @@ import path from "path"; code: number; reportsUnnecessary?: {}; reportsDeprecated?: {}; + reportsExperimental?: {}; isEarly?: boolean; elidedInCompatabilityPyramid?: boolean; }} DiagnosticDetails */ @@ -88,7 +89,7 @@ function buildInfoFileOutput(messageTable, inputFilePathRel) { "", 'import { DiagnosticCategory, DiagnosticMessage } from "./types.js";', "", - "function diag(code: number, category: DiagnosticCategory, key: string, message: string, reportsUnnecessary?: {}, elidedInCompatabilityPyramid?: boolean, reportsDeprecated?: {}): DiagnosticMessage {", + "function diag(code: number, category: DiagnosticCategory, key: string, message: string, reportsUnnecessary?: {}, elidedInCompatabilityPyramid?: boolean, reportsDeprecated?: {}, reportsExperimental?: {}): DiagnosticMessage {", " return { code, category, key, message, reportsUnnecessary, elidedInCompatabilityPyramid, reportsDeprecated };", "}", "", @@ -96,13 +97,14 @@ function buildInfoFileOutput(messageTable, inputFilePathRel) { "/** @internal */", "export const Diagnostics = {", ]; - messageTable.forEach(({ code, category, reportsUnnecessary, elidedInCompatabilityPyramid, reportsDeprecated }, name) => { + messageTable.forEach(({ code, category, reportsUnnecessary, elidedInCompatabilityPyramid, reportsDeprecated, reportsExperimental }, name) => { const propName = convertPropertyName(name); const argReportsUnnecessary = reportsUnnecessary ? `, /*reportsUnnecessary*/ ${reportsUnnecessary}` : ""; const argElidedInCompatabilityPyramid = elidedInCompatabilityPyramid ? `${!reportsUnnecessary ? ", /*reportsUnnecessary*/ undefined" : ""}, /*elidedInCompatabilityPyramid*/ ${elidedInCompatabilityPyramid}` : ""; const argReportsDeprecated = reportsDeprecated ? `${!argElidedInCompatabilityPyramid ? ", /*reportsUnnecessary*/ undefined, /*elidedInCompatabilityPyramid*/ undefined" : ""}, /*reportsDeprecated*/ ${reportsDeprecated}` : ""; + const argReportsExperimental = reportsExperimental ? `${!argElidedInCompatabilityPyramid ? ", /*reportsUnnecessary*/ undefined, /*elidedInCompatabilityPyramid*/ undefined" : ""}, /*reportsExperimental*/ ${reportsExperimental}` : ""; - result.push(` ${propName}: diag(${code}, DiagnosticCategory.${category}, "${createKey(propName, code)}", ${JSON.stringify(name)}${argReportsUnnecessary}${argElidedInCompatabilityPyramid}${argReportsDeprecated}) as DiagnosticMessage,`); + result.push(` ${propName}: diag(${code}, DiagnosticCategory.${category}, "${createKey(propName, code)}", ${JSON.stringify(name)}${argReportsUnnecessary}${argElidedInCompatabilityPyramid}${argReportsDeprecated}${argReportsExperimental}) as DiagnosticMessage,`); }); result.push("};"); diff --git a/src/compiler/builder.ts b/src/compiler/builder.ts index 1c472cebead0d..c240dafe015c6 100644 --- a/src/compiler/builder.ts +++ b/src/compiler/builder.ts @@ -96,6 +96,7 @@ export interface ReusableDiagnostic extends ReusableDiagnosticRelatedInformation /** May store more in future. For now, this will simply be `true` to indicate when a diagnostic is an unused-identifier diagnostic. */ reportsUnnecessary?: {}; reportDeprecated?: {}; + reportsExperimental?: {}; source?: string; relatedInformation?: ReusableDiagnosticRelatedInformation[]; skippedOn?: keyof CompilerOptions; @@ -575,6 +576,7 @@ function convertToDiagnostics( const result: Diagnostic = convertToDiagnosticRelatedInformation(diagnostic, diagnosticFilePath, newProgram, toPathInBuildInfoDirectory); result.reportsUnnecessary = diagnostic.reportsUnnecessary; result.reportsDeprecated = diagnostic.reportDeprecated; + result.reportsExperimental = diagnostic.reportsExperimental; result.source = diagnostic.source; result.skippedOn = diagnostic.skippedOn; const { relatedInformation } = diagnostic; @@ -1505,6 +1507,7 @@ function getBuildInfo(state: BuilderProgramStateWithDefinedProgram): BuildInfo { const result: ReusableDiagnostic = toReusableDiagnosticRelatedInformation(diagnostic, diagnosticFilePath); result.reportsUnnecessary = diagnostic.reportsUnnecessary; result.reportDeprecated = diagnostic.reportsDeprecated; + result.reportsExperimental = diagnostic.reportsExperimental; result.source = diagnostic.source; result.skippedOn = diagnostic.skippedOn; const { relatedInformation } = diagnostic; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 0dc9b7ccb34fa..7b4c93c6da328 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -1845,6 +1845,7 @@ namespace Parser { } let hasDeprecatedTag = false; + let hasExperimentalTag = false; function withJSDoc(node: T, hasJSDoc: boolean): T { if (!hasJSDoc) { return node; @@ -1857,6 +1858,10 @@ namespace Parser { hasDeprecatedTag = false; (node as Mutable).flags |= NodeFlags.Deprecated; } + if (hasExperimentalTag) { + hasExperimentalTag = false; + (node as Mutable).flags |= NodeFlags.Experimental; + } return node; } @@ -9091,6 +9096,10 @@ namespace Parser { hasDeprecatedTag = true; tag = parseSimpleTag(start, factory.createJSDocDeprecatedTag, tagName, margin, indentText); break; + case "experimental": + hasExperimentalTag = true; + tag = parseSimpleTag(start, factory.createJSDocExperimentalTag, tagName, margin, indentText); + break; case "this": tag = parseThisTag(start, tagName, margin, indentText); break; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index b4d43c21ff468..e7c719aeae1cb 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -8582,6 +8582,7 @@ export function createFileDiagnostic(file: SourceFile, start: number, length: nu code: message.code, reportsUnnecessary: message.reportsUnnecessary, reportsDeprecated: message.reportsDeprecated, + reportsExperimental: message.reportsExperimental, }; } @@ -8599,8 +8600,6 @@ export function formatMessage(message: DiagnosticMessage, ...args: DiagnosticArg /** @internal */ export function createCompilerDiagnostic(message: DiagnosticMessage, ...args: DiagnosticArguments): Diagnostic { let text = getLocaleSpecificMessage(message); - //@ts-ignore - console.log(text) if (some(args)) { text = formatStringFromArgs(text, args); @@ -8616,6 +8615,7 @@ export function createCompilerDiagnostic(message: DiagnosticMessage, ...args: Di code: message.code, reportsUnnecessary: message.reportsUnnecessary, reportsDeprecated: message.reportsDeprecated, + reportsExperimental: message.reportsExperimental, }; } diff --git a/src/harness/client.ts b/src/harness/client.ts index 88458aa197d13..1b4e847d6b239 100644 --- a/src/harness/client.ts +++ b/src/harness/client.ts @@ -529,6 +529,7 @@ export class SessionClient implements LanguageService { code: entry.code, reportsUnnecessary: entry.reportsUnnecessary, reportsDeprecated: entry.reportsDeprecated, + reportsExperimental: entry.reportsExperimental, }; }); } diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts index e83d4bf1d5124..f439ad83268c9 100644 --- a/src/harness/fourslashImpl.ts +++ b/src/harness/fourslashImpl.ts @@ -215,6 +215,7 @@ interface RealizedDiagnostic { code: number; reportsUnnecessary?: {}; reportsDeprecated?: {}; + reportsExperimental?: {}; } function realizeDiagnostics(diagnostics: readonly ts.Diagnostic[], newLine: string): RealizedDiagnostic[] { @@ -230,6 +231,7 @@ function realizeDiagnostic(diagnostic: ts.Diagnostic, newLine: string): Realized code: diagnostic.code, reportsUnnecessary: diagnostic.reportsUnnecessary, reportsDeprecated: diagnostic.reportsDeprecated, + reportsExperimental: diagnostic.reportsExperimental }; } @@ -1898,6 +1900,7 @@ export class TestState { ...ts.createTextSpanFromRange(range), reportsUnnecessary: e.reportsUnnecessary, reportsDeprecated: e.reportsDeprecated, + reportsExperimental: e.reportsExperimental, }; }), ); diff --git a/src/harness/fourslashInterfaceImpl.ts b/src/harness/fourslashInterfaceImpl.ts index 0dd8236f94b75..165edd50a8e12 100644 --- a/src/harness/fourslashInterfaceImpl.ts +++ b/src/harness/fourslashInterfaceImpl.ts @@ -60,6 +60,7 @@ export class Test { code: tsDiag.code, reportsUnnecessary: tsDiag.reportsUnnecessary ? true : undefined, reportsDeprecated: !!tsDiag.reportsDeprecated ? true : undefined, + reportsExperimental: !!tsDiag.reportsExperimental ? true : undefined, })); } } @@ -2004,6 +2005,7 @@ export interface Diagnostic { code: number; reportsUnnecessary?: true; reportsDeprecated?: true; + reportsExperimental?: true; } export interface GetEditsForFileRenameOptions { diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 8c2948de7f242..50df49341ff54 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -582,6 +582,7 @@ export interface DiagnosticWithLinePosition { /** May store more in future. For now, this will simply be `true` to indicate when a diagnostic is an unused-identifier diagnostic. */ reportsUnnecessary?: {}; reportsDeprecated?: {}; + reportsExperimental?: {}; relatedInformation?: DiagnosticRelatedInformation[]; } @@ -2592,6 +2593,8 @@ export interface Diagnostic { reportsDeprecated?: {}; + reportsExperimental?: {}; + /** * Any related spans the diagnostic may have, such as other locations relevant to an error, such as declarartion sites */ diff --git a/src/server/session.ts b/src/server/session.ts index 2c2f2895f01a4..ad9234e36ceee 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -244,6 +244,7 @@ function formatDiag(fileName: NormalizedPath, project: Project, diag: Diagnostic category: diagnosticCategoryName(diag), reportsUnnecessary: diag.reportsUnnecessary, reportsDeprecated: diag.reportsDeprecated, + reportsExperimental: diag.reportsExperimental, source: diag.source, relatedInformation: map(diag.relatedInformation, formatRelatedInformation), }; @@ -292,6 +293,7 @@ export function formatDiagnosticToProtocol(diag: Diagnostic, includeFileName: bo category, reportsUnnecessary: diag.reportsUnnecessary, reportsDeprecated: diag.reportsDeprecated, + reportsExperimental: diag.reportsExperimental, source, relatedInformation: map(diag.relatedInformation, formatRelatedInformation), }; @@ -1555,6 +1557,7 @@ export class Session implements EventSender { endLocation: (d.file && convertToLocation(getLineAndCharacterOfPosition(d.file, d.start! + d.length!)))!, // TODO: GH#18217 reportsUnnecessary: d.reportsUnnecessary, reportsDeprecated: d.reportsDeprecated, + reportsExperimental: d.reportsExperimental, relatedInformation: map(d.relatedInformation, formatRelatedInformation), })); } @@ -1586,6 +1589,7 @@ export class Session implements EventSender { endLocation: scriptInfo && scriptInfo.positionToLineOffset(d.start! + d.length!), reportsUnnecessary: d.reportsUnnecessary, reportsDeprecated: d.reportsDeprecated, + reportsExperimental: d.reportsExperimental, relatedInformation: map(d.relatedInformation, formatRelatedInformation), }) as protocol.DiagnosticWithLinePosition ); diff --git a/src/testRunner/unittests/tscWatch/incremental.ts b/src/testRunner/unittests/tscWatch/incremental.ts index 30114dc48f8a2..d76a75c65d684 100644 --- a/src/testRunner/unittests/tscWatch/incremental.ts +++ b/src/testRunner/unittests/tscWatch/incremental.ts @@ -219,6 +219,7 @@ describe("unittests:: tscWatch:: incremental:: emit file --incremental", () => { relatedInformation: undefined, reportsUnnecessary: undefined, reportsDeprecated: undefined, + reportsExperimental: undefined, source: undefined, skippedOn: undefined, }]); diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index f8dab87affd37..3c69bf3cf1ec9 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -441,6 +441,7 @@ declare namespace ts { /** May store more in future. For now, this will simply be `true` to indicate when a diagnostic is an unused-identifier diagnostic. */ reportsUnnecessary?: {}; reportsDeprecated?: {}; + reportsExperimental?: {}; relatedInformation?: DiagnosticRelatedInformation[]; } /** @@ -1986,6 +1987,7 @@ declare namespace ts { category: string; reportsUnnecessary?: {}; reportsDeprecated?: {}; + reportsExperimental?: {}; /** * Any related spans the diagnostic may have, such as other locations relevant to an error, such as declarartion sites */ diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 4589a13a8a3cb..aa8d88693b7a4 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -323,7 +323,7 @@ declare namespace FourSlashInterface { * to 'value'. Do not use this function with external modules as it is not supported. */ eval(expr: string, value: any): void; - curentLineContentIs(text: string): void; + currentLineContentIs(text: string): void; currentFileContentIs(text: string): void; formatDocumentChangesNothing(): void; verifyGetEmitOutputForCurrentFile(expected: string): void;