mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-07 05:41:22 -06:00
Rewrite logic for JSX attribute completion detection [4.5 cherry pick] (#47413)
This commit is contained in:
parent
14016a7851
commit
8a8048fb62
@ -428,6 +428,7 @@ namespace ts.Completions {
|
||||
isJsxInitializer,
|
||||
isTypeOnlyLocation,
|
||||
isJsxIdentifierExpected,
|
||||
isRightOfOpenTag,
|
||||
importCompletionNode,
|
||||
insideJsDocTagTypeExpression,
|
||||
symbolToSortTextIdMap,
|
||||
@ -466,7 +467,9 @@ namespace ts.Completions {
|
||||
importCompletionNode,
|
||||
recommendedCompletion,
|
||||
symbolToOriginInfoMap,
|
||||
symbolToSortTextIdMap
|
||||
symbolToSortTextIdMap,
|
||||
isJsxIdentifierExpected,
|
||||
isRightOfOpenTag,
|
||||
);
|
||||
getJSCompletionEntries(sourceFile, location.pos, uniqueNames, getEmitScriptTarget(compilerOptions), entries); // TODO: GH#18217
|
||||
}
|
||||
@ -496,7 +499,9 @@ namespace ts.Completions {
|
||||
importCompletionNode,
|
||||
recommendedCompletion,
|
||||
symbolToOriginInfoMap,
|
||||
symbolToSortTextIdMap
|
||||
symbolToSortTextIdMap,
|
||||
isJsxIdentifierExpected,
|
||||
isRightOfOpenTag,
|
||||
);
|
||||
}
|
||||
|
||||
@ -638,6 +643,8 @@ namespace ts.Completions {
|
||||
options: CompilerOptions,
|
||||
preferences: UserPreferences,
|
||||
completionKind: CompletionKind,
|
||||
isJsxIdentifierExpected: boolean | undefined,
|
||||
isRightOfOpenTag: boolean | undefined,
|
||||
): CompletionEntry | undefined {
|
||||
let insertText: string | undefined;
|
||||
let replacementSpan = getReplacementSpanForContextToken(replacementToken);
|
||||
@ -713,25 +720,7 @@ namespace ts.Completions {
|
||||
}
|
||||
}
|
||||
|
||||
// Before offering up a JSX attribute snippet, ensure that we aren't potentially completing
|
||||
// a tag name; this may appear as an attribute after the "<" when the tag has not yet been
|
||||
// closed, as in:
|
||||
//
|
||||
// return <>
|
||||
// foo <butto|
|
||||
// </>
|
||||
//
|
||||
// We can detect this case by checking if both:
|
||||
//
|
||||
// 1. The location is "<", so we are completing immediately after it.
|
||||
// 2. The "<" has the same position as its parent, so is not a binary expression.
|
||||
const kind = SymbolDisplay.getSymbolKind(typeChecker, symbol, location);
|
||||
if (
|
||||
kind === ScriptElementKind.jsxAttribute
|
||||
&& (location.kind !== SyntaxKind.LessThanToken || location.pos !== location.parent.pos)
|
||||
&& preferences.includeCompletionsWithSnippetText
|
||||
&& preferences.jsxAttributeCompletionStyle
|
||||
&& preferences.jsxAttributeCompletionStyle !== "none") {
|
||||
if (isJsxIdentifierExpected && !isRightOfOpenTag && preferences.includeCompletionsWithSnippetText && preferences.jsxAttributeCompletionStyle && preferences.jsxAttributeCompletionStyle !== "none") {
|
||||
let useBraces = preferences.jsxAttributeCompletionStyle === "braces";
|
||||
const type = typeChecker.getTypeOfSymbolAtLocation(symbol, location);
|
||||
|
||||
@ -776,7 +765,7 @@ namespace ts.Completions {
|
||||
// entries (like JavaScript identifier entries).
|
||||
return {
|
||||
name,
|
||||
kind,
|
||||
kind: SymbolDisplay.getSymbolKind(typeChecker, symbol, location),
|
||||
kindModifiers: SymbolDisplay.getSymbolModifiers(typeChecker, symbol),
|
||||
sortText,
|
||||
source,
|
||||
@ -1142,6 +1131,8 @@ namespace ts.Completions {
|
||||
recommendedCompletion?: Symbol,
|
||||
symbolToOriginInfoMap?: SymbolOriginInfoMap,
|
||||
symbolToSortTextIdMap?: SymbolSortTextIdMap,
|
||||
isJsxIdentifierExpected?: boolean,
|
||||
isRightOfOpenTag?: boolean,
|
||||
): UniqueNameSet {
|
||||
const start = timestamp();
|
||||
const variableDeclaration = getVariableDeclaration(location);
|
||||
@ -1183,6 +1174,8 @@ namespace ts.Completions {
|
||||
compilerOptions,
|
||||
preferences,
|
||||
kind,
|
||||
isJsxIdentifierExpected,
|
||||
isRightOfOpenTag,
|
||||
);
|
||||
if (!entry) {
|
||||
continue;
|
||||
@ -1534,6 +1527,7 @@ namespace ts.Completions {
|
||||
readonly isTypeOnlyLocation: boolean;
|
||||
/** In JSX tag name and attribute names, identifiers like "my-tag" or "aria-name" is valid identifier. */
|
||||
readonly isJsxIdentifierExpected: boolean;
|
||||
readonly isRightOfOpenTag: boolean;
|
||||
readonly importCompletionNode?: Node;
|
||||
readonly hasUnresolvedAutoImports?: boolean;
|
||||
}
|
||||
@ -1941,6 +1935,7 @@ namespace ts.Completions {
|
||||
symbolToSortTextIdMap,
|
||||
isTypeOnlyLocation,
|
||||
isJsxIdentifierExpected,
|
||||
isRightOfOpenTag,
|
||||
importCompletionNode,
|
||||
hasUnresolvedAutoImports,
|
||||
};
|
||||
|
||||
@ -1,61 +0,0 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
//@Filename: file.tsx
|
||||
////declare namespace JSX {
|
||||
//// interface IntrinsicElements {
|
||||
//// button: any;
|
||||
//// div: any;
|
||||
//// }
|
||||
////}
|
||||
////function fn() {
|
||||
//// return <>
|
||||
//// <butto/*1*/
|
||||
//// </>;
|
||||
////}
|
||||
////function fn2() {
|
||||
//// return <>
|
||||
//// preceding junk <butto/*2*/
|
||||
//// </>;
|
||||
////}
|
||||
////function fn3() {
|
||||
//// return <>
|
||||
//// <butto/*3*/ style=""
|
||||
//// </>;
|
||||
////}
|
||||
|
||||
|
||||
|
||||
verify.completions(
|
||||
{
|
||||
marker: "1",
|
||||
includes: [
|
||||
{ name: "button", insertText: undefined, isSnippet: undefined }
|
||||
],
|
||||
preferences: {
|
||||
jsxAttributeCompletionStyle: "braces",
|
||||
includeCompletionsWithSnippetText: true,
|
||||
includeCompletionsWithInsertText: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
marker: "2",
|
||||
includes: [
|
||||
{ name: "button", insertText: undefined, isSnippet: undefined }
|
||||
],
|
||||
preferences: {
|
||||
jsxAttributeCompletionStyle: "braces",
|
||||
includeCompletionsWithSnippetText: true,
|
||||
includeCompletionsWithInsertText: true,
|
||||
}
|
||||
},
|
||||
{
|
||||
marker: "3",
|
||||
includes: [
|
||||
{ name: "button", insertText: undefined, isSnippet: undefined }
|
||||
],
|
||||
preferences: {
|
||||
jsxAttributeCompletionStyle: "braces",
|
||||
includeCompletionsWithSnippetText: true,
|
||||
includeCompletionsWithInsertText: true,
|
||||
}
|
||||
},
|
||||
);
|
||||
74
tests/cases/fourslash/jsxAttributeSnippetCompletionClosed.ts
Normal file
74
tests/cases/fourslash/jsxAttributeSnippetCompletionClosed.ts
Normal file
@ -0,0 +1,74 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
//@Filename: file.tsx
|
||||
////interface NestedInterface {
|
||||
//// Foo: NestedInterface;
|
||||
//// (props: {className?: string}): any;
|
||||
////}
|
||||
////
|
||||
////declare const Foo: NestedInterface;
|
||||
////
|
||||
////function fn1() {
|
||||
//// return <Foo>
|
||||
//// <Foo /*1*/ />
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn2() {
|
||||
//// return <Foo>
|
||||
//// <Foo.Foo /*2*/ />
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn3() {
|
||||
//// return <Foo>
|
||||
//// <Foo.Foo cla/*3*/ />
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn4() {
|
||||
//// return <Foo>
|
||||
//// <Foo.Foo cla/*4*/ something />
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn5() {
|
||||
//// return <Foo>
|
||||
//// <Foo.Foo something /*5*/ />
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn6() {
|
||||
//// return <Foo>
|
||||
//// <Foo.Foo something cla/*6*/ />
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn7() {
|
||||
//// return <Foo /*7*/ />
|
||||
////}
|
||||
////function fn8() {
|
||||
//// return <Foo cla/*8*/ />
|
||||
////}
|
||||
////function fn9() {
|
||||
//// return <Foo cla/*9*/ something />
|
||||
////}
|
||||
////function fn10() {
|
||||
//// return <Foo something /*10*/ />
|
||||
////}
|
||||
////function fn11() {
|
||||
//// return <Foo something cla/*11*/ />
|
||||
////}
|
||||
|
||||
var preferences: FourSlashInterface.UserPreferences = {
|
||||
jsxAttributeCompletionStyle: "braces",
|
||||
includeCompletionsWithSnippetText: true,
|
||||
includeCompletionsWithInsertText: true,
|
||||
};
|
||||
|
||||
verify.completions(
|
||||
{ marker: "1", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "2", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "3", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "4", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "5", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "6", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "7", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "8", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "9", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "10", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "11", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
)
|
||||
@ -0,0 +1,74 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
//@Filename: file.tsx
|
||||
////interface NestedInterface {
|
||||
//// Foo: NestedInterface;
|
||||
//// (props: {className?: string}): any;
|
||||
////}
|
||||
////
|
||||
////declare const Foo: NestedInterface;
|
||||
////
|
||||
////function fn1() {
|
||||
//// return <Foo>
|
||||
//// <Foo /*1*/
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn2() {
|
||||
//// return <Foo>
|
||||
//// <Foo.Foo /*2*/
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn3() {
|
||||
//// return <Foo>
|
||||
//// <Foo.Foo cla/*3*/
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn4() {
|
||||
//// return <Foo>
|
||||
//// <Foo.Foo cla/*4*/ something
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn5() {
|
||||
//// return <Foo>
|
||||
//// <Foo.Foo something /*5*/
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn6() {
|
||||
//// return <Foo>
|
||||
//// <Foo.Foo something cla/*6*/
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn7() {
|
||||
//// return <Foo /*7*/
|
||||
////}
|
||||
////function fn8() {
|
||||
//// return <Foo cla/*8*/
|
||||
////}
|
||||
////function fn9() {
|
||||
//// return <Foo cla/*9*/ something
|
||||
////}
|
||||
////function fn10() {
|
||||
//// return <Foo something /*10*/
|
||||
////}
|
||||
////function fn11() {
|
||||
//// return <Foo something cla/*11*/
|
||||
////}
|
||||
|
||||
var preferences: FourSlashInterface.UserPreferences = {
|
||||
jsxAttributeCompletionStyle: "braces",
|
||||
includeCompletionsWithSnippetText: true,
|
||||
includeCompletionsWithInsertText: true,
|
||||
};
|
||||
|
||||
verify.completions(
|
||||
{ marker: "1", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "2", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "3", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "4", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "5", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "6", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "7", preferences, includes: { name: "className", insertText: "className={$1}", text: "(property) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "8", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "9", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "10", preferences, includes: { name: "className", insertText: "className={$1}", text: "(property) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
{ marker: "11", preferences, includes: { name: "className", insertText: "className={$1}", text: "(JSX attribute) className?: string", isSnippet: true, sortText: completion.SortText.OptionalMember } },
|
||||
)
|
||||
54
tests/cases/fourslash/jsxTagNameCompletionClosed.ts
Normal file
54
tests/cases/fourslash/jsxTagNameCompletionClosed.ts
Normal file
@ -0,0 +1,54 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
//@Filename: file.tsx
|
||||
////interface NestedInterface {
|
||||
//// Foo: NestedInterface;
|
||||
//// (props: {}): any;
|
||||
////}
|
||||
////
|
||||
////declare const Foo: NestedInterface;
|
||||
////
|
||||
////function fn1() {
|
||||
//// return <Foo>
|
||||
//// </*1*/ />
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn2() {
|
||||
//// return <Foo>
|
||||
//// <Fo/*2*/ />
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn3() {
|
||||
//// return <Foo>
|
||||
//// <Foo./*3*/ />
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn4() {
|
||||
//// return <Foo>
|
||||
//// <Foo.F/*4*/ />
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn5() {
|
||||
//// return <Foo>
|
||||
//// <Foo.Foo./*5*/ />
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn6() {
|
||||
//// return <Foo>
|
||||
//// <Foo.Foo.F/*6*/ />
|
||||
//// </Foo>
|
||||
////}
|
||||
|
||||
var preferences: FourSlashInterface.UserPreferences = {
|
||||
jsxAttributeCompletionStyle: "braces",
|
||||
includeCompletionsWithSnippetText: true,
|
||||
includeCompletionsWithInsertText: true,
|
||||
};
|
||||
|
||||
verify.completions(
|
||||
{ marker: "1", preferences, includes: { name: "Foo", text: "const Foo: NestedInterface" } },
|
||||
{ marker: "2", preferences, includes: { name: "Foo", text: "const Foo: NestedInterface" } },
|
||||
{ marker: "3", preferences, includes: { name: "Foo", text: "(JSX attribute) NestedInterface.Foo: NestedInterface" } },
|
||||
{ marker: "4", preferences, includes: { name: "Foo", text: "(property) NestedInterface.Foo: NestedInterface" } },
|
||||
{ marker: "5", preferences, includes: { name: "Foo", text: "(JSX attribute) NestedInterface.Foo: NestedInterface" } },
|
||||
{ marker: "6", preferences, includes: { name: "Foo", text: "(property) NestedInterface.Foo: NestedInterface" } },
|
||||
)
|
||||
54
tests/cases/fourslash/jsxTagNameCompletionUnclosed.ts
Normal file
54
tests/cases/fourslash/jsxTagNameCompletionUnclosed.ts
Normal file
@ -0,0 +1,54 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
//@Filename: file.tsx
|
||||
////interface NestedInterface {
|
||||
//// Foo: NestedInterface;
|
||||
//// (props: {}): any;
|
||||
////}
|
||||
////
|
||||
////declare const Foo: NestedInterface;
|
||||
////
|
||||
////function fn1() {
|
||||
//// return <Foo>
|
||||
//// </*1*/
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn2() {
|
||||
//// return <Foo>
|
||||
//// <Fo/*2*/
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn3() {
|
||||
//// return <Foo>
|
||||
//// <Foo./*3*/
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn4() {
|
||||
//// return <Foo>
|
||||
//// <Foo.F/*4*/
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn5() {
|
||||
//// return <Foo>
|
||||
//// <Foo.Foo./*5*/
|
||||
//// </Foo>
|
||||
////}
|
||||
////function fn6() {
|
||||
//// return <Foo>
|
||||
//// <Foo.Foo.F/*6*/
|
||||
//// </Foo>
|
||||
////}
|
||||
|
||||
var preferences: FourSlashInterface.UserPreferences = {
|
||||
jsxAttributeCompletionStyle: "braces",
|
||||
includeCompletionsWithSnippetText: true,
|
||||
includeCompletionsWithInsertText: true,
|
||||
};
|
||||
|
||||
verify.completions(
|
||||
{ marker: "1", preferences, includes: { name: "Foo", text: "const Foo: NestedInterface" } },
|
||||
{ marker: "2", preferences, includes: { name: "Foo", text: "const Foo: NestedInterface" } },
|
||||
{ marker: "3", preferences, includes: { name: "Foo", text: "(JSX attribute) NestedInterface.Foo: NestedInterface" } },
|
||||
{ marker: "4", preferences, includes: { name: "Foo", text: "(property) NestedInterface.Foo: NestedInterface" } },
|
||||
{ marker: "5", preferences, includes: { name: "Foo", text: "(JSX attribute) NestedInterface.Foo: NestedInterface" } },
|
||||
{ marker: "6", preferences, includes: { name: "Foo", text: "(property) NestedInterface.Foo: NestedInterface" } },
|
||||
)
|
||||
@ -0,0 +1,35 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
//@Filename: file.tsx
|
||||
////declare namespace JSX {
|
||||
//// interface IntrinsicElements {
|
||||
//// button: any;
|
||||
//// div: any;
|
||||
//// }
|
||||
////}
|
||||
////function fn() {
|
||||
//// return <>
|
||||
//// <butto/*1*/ />
|
||||
//// </>;
|
||||
////}
|
||||
////function fn2() {
|
||||
//// return <>
|
||||
//// preceding junk <butto/*2*/ />
|
||||
//// </>;
|
||||
////}
|
||||
////function fn3() {
|
||||
//// return <>
|
||||
//// <butto/*3*/ style="" />
|
||||
//// </>;
|
||||
////}
|
||||
|
||||
var preferences: FourSlashInterface.UserPreferences = {
|
||||
jsxAttributeCompletionStyle: "braces",
|
||||
includeCompletionsWithSnippetText: true,
|
||||
includeCompletionsWithInsertText: true,
|
||||
};
|
||||
|
||||
verify.completions(
|
||||
{ marker: "1", preferences, includes: { name: "button", text: "(JSX attribute) JSX.IntrinsicElements.button: any" } },
|
||||
{ marker: "2", preferences, includes: { name: "button", text: "(JSX attribute) JSX.IntrinsicElements.button: any" } },
|
||||
{ marker: "3", preferences, includes: { name: "button", text: "(JSX attribute) JSX.IntrinsicElements.button: any" } },
|
||||
)
|
||||
@ -0,0 +1,35 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
//@Filename: file.tsx
|
||||
////declare namespace JSX {
|
||||
//// interface IntrinsicElements {
|
||||
//// button: any;
|
||||
//// div: any;
|
||||
//// }
|
||||
////}
|
||||
////function fn() {
|
||||
//// return <>
|
||||
//// <butto/*1*/
|
||||
//// </>;
|
||||
////}
|
||||
////function fn2() {
|
||||
//// return <>
|
||||
//// preceding junk <butto/*2*/
|
||||
//// </>;
|
||||
////}
|
||||
////function fn3() {
|
||||
//// return <>
|
||||
//// <butto/*3*/ style=""
|
||||
//// </>;
|
||||
////}
|
||||
|
||||
var preferences: FourSlashInterface.UserPreferences = {
|
||||
jsxAttributeCompletionStyle: "braces",
|
||||
includeCompletionsWithSnippetText: true,
|
||||
includeCompletionsWithInsertText: true,
|
||||
};
|
||||
|
||||
verify.completions(
|
||||
{ marker: "1", preferences, includes: { name: "button", text: "(JSX attribute) JSX.IntrinsicElements.button: any" } },
|
||||
{ marker: "2", preferences, includes: { name: "button", text: "(JSX attribute) JSX.IntrinsicElements.button: any" } },
|
||||
{ marker: "3", preferences, includes: { name: "button", text: "(JSX attribute) JSX.IntrinsicElements.button: any" } },
|
||||
)
|
||||
Loading…
x
Reference in New Issue
Block a user