diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index a2ed0feb795a7..209acabc0694c 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -149,6 +149,7 @@ import { isJsxClosingElement, isJsxElement, isJsxFragment, + isJsxNamespacedName, isJsxOpeningElement, isJsxSelfClosingElement, isJumpStatementTarget, @@ -202,6 +203,7 @@ import { isVoidExpression, isWriteAccess, JSDocPropertyLikeTag, + JsxNamespacedName, length, map, mapDefined, @@ -325,7 +327,7 @@ export interface SpanEntry { function nodeEntry(node: Node, kind: NodeEntryKind = EntryKind.Node): NodeEntry { return { kind, - node: (node as NamedDeclaration).name || node, + node: isJsxNamespacedName(node) ? node : ((node as NamedDeclaration).name || node), context: getContextNodeForNodeEntry(node), }; } @@ -1835,6 +1837,10 @@ export namespace Core { // falls through I guess case SyntaxKind.Identifier: return (node as PrivateIdentifier | Identifier).text.length === searchSymbolName.length; + case SyntaxKind.JsxNamespacedName: { + const { namespace, name } = node as JsxNamespacedName; + return (namespace.text.length + 1 + name.text.length) === searchSymbolName.length; + } case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.StringLiteral: { const str = node as StringLiteralLike; diff --git a/src/services/rename.ts b/src/services/rename.ts index be533ff0b4230..01cdb0ab78d1c 100644 --- a/src/services/rename.ts +++ b/src/services/rename.ts @@ -235,6 +235,7 @@ export function nodeIsEligibleForRename(node: Node): boolean { case SyntaxKind.StringLiteral: case SyntaxKind.NoSubstitutionTemplateLiteral: case SyntaxKind.ThisKeyword: + case SyntaxKind.JsxNamespacedName: return true; case SyntaxKind.NumericLiteral: return isLiteralNameOfPropertyDeclarationOrIndexAccess(node as NumericLiteral); diff --git a/src/services/services.ts b/src/services/services.ts index 2df3b75ae6cb7..ca5a33a9259f5 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -3497,7 +3497,7 @@ export function getNameTable(sourceFile: SourceFile): Map<__String, number> { function initializeNameTable(sourceFile: SourceFile): void { const nameTable = sourceFile.nameTable = new Map(); sourceFile.forEachChild(function walk(node) { - if (isIdentifier(node) && !isTagName(node) && node.escapedText || isStringOrNumericLiteralLike(node) && literalIsName(node)) { + if (isIdentifier(node) && !isTagName(node) && node.escapedText || isStringOrNumericLiteralLike(node) && literalIsName(node) || isJsxNamespacedName(node)) { const text = getEscapedTextOfIdentifierOrLiteral(node); nameTable.set(text, nameTable.get(text) === undefined ? node.pos : -1); } diff --git a/src/services/utilities.ts b/src/services/utilities.ts index ceb56323ceeb6..160f56f68415c 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -203,6 +203,7 @@ import { isJSDocTypeAlias, isJsxElement, isJsxExpression, + isJsxNamespacedName, isJsxOpeningLikeElement, isJsxText, isKeyword, @@ -1547,7 +1548,8 @@ export function getAdjustedRenameLocation(node: Node): Node { * @internal */ export function getTouchingPropertyName(sourceFile: SourceFile, position: number): Node { - return getTouchingToken(sourceFile, position, n => isPropertyNameLiteral(n) || isKeyword(n.kind) || isPrivateIdentifier(n)); + const token = getTouchingToken(sourceFile, position, n => isPropertyNameLiteral(n) || isKeyword(n.kind) || isPrivateIdentifier(n)); + return isIdentifier(token) && isJsxNamespacedName(token.parent) ? token.parent : token; } /** diff --git a/tests/baselines/reference/findAllReferencesOnJsxNamespacedName1.baseline.jsonc b/tests/baselines/reference/findAllReferencesOnJsxNamespacedName1.baseline.jsonc new file mode 100644 index 0000000000000..32087f986df19 --- /dev/null +++ b/tests/baselines/reference/findAllReferencesOnJsxNamespacedName1.baseline.jsonc @@ -0,0 +1,204 @@ +// === findAllReferences === +// === /types.d.ts === +// declare namespace JSX { +// interface IntrinsicElements { +// 'my-el': { +// <|'[|{| isWriteAccess: true |}prop:foo|]': string;|> +// }; +// } +// } + +// === /a.tsx === +// /> + + // === Definitions === + // === /types.d.ts === + // declare namespace JSX { + // interface IntrinsicElements { + // 'my-el': { + // <|'[|prop:foo|]': string;|> + // }; + // } + // } + + // === Details === + [ + { + "containerKind": "", + "containerName": "", + "kind": "property", + "name": "(property) 'prop:foo': string", + "displayParts": [ + { + "text": "(", + "kind": "punctuation" + }, + { + "text": "property", + "kind": "text" + }, + { + "text": ")", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "'prop:foo'", + "kind": "propertyName" + }, + { + "text": ":", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "string", + "kind": "keyword" + } + ] + } + ] + + + +// === findAllReferences === +// === /types.d.ts === +// declare namespace JSX { +// interface IntrinsicElements { +// 'my-el': { +// <|'[|{| isWriteAccess: true |}prop:foo|]': string;|> +// }; +// } +// } + +// === /a.tsx === +// /> + + // === Definitions === + // === /types.d.ts === + // declare namespace JSX { + // interface IntrinsicElements { + // 'my-el': { + // <|'[|prop:foo|]': string;|> + // }; + // } + // } + + // === Details === + [ + { + "containerKind": "", + "containerName": "", + "kind": "property", + "name": "(property) 'prop:foo': string", + "displayParts": [ + { + "text": "(", + "kind": "punctuation" + }, + { + "text": "property", + "kind": "text" + }, + { + "text": ")", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "'prop:foo'", + "kind": "propertyName" + }, + { + "text": ":", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "string", + "kind": "keyword" + } + ] + } + ] + + + +// === findAllReferences === +// === /types.d.ts === +// declare namespace JSX { +// interface IntrinsicElements { +// 'my-el': { +// <|'/*FIND ALL REFS*/[|{| isWriteAccess: true, isDefinition: true |}prop:foo|]': string;|> +// }; +// } +// } + +// === /a.tsx === +// /> + + // === Definitions === + // === /types.d.ts === + // declare namespace JSX { + // interface IntrinsicElements { + // 'my-el': { + // <|'/*FIND ALL REFS*/[|prop:foo|]': string;|> + // }; + // } + // } + + // === Details === + [ + { + "containerKind": "", + "containerName": "", + "kind": "property", + "name": "(property) 'prop:foo': string", + "displayParts": [ + { + "text": "(", + "kind": "punctuation" + }, + { + "text": "property", + "kind": "text" + }, + { + "text": ")", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "'prop:foo'", + "kind": "propertyName" + }, + { + "text": ":", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "string", + "kind": "keyword" + } + ] + } + ] \ No newline at end of file diff --git a/tests/baselines/reference/findAllReferencesOnJsxNamespacedName2.baseline.jsonc b/tests/baselines/reference/findAllReferencesOnJsxNamespacedName2.baseline.jsonc new file mode 100644 index 0000000000000..6072f06f32845 --- /dev/null +++ b/tests/baselines/reference/findAllReferencesOnJsxNamespacedName2.baseline.jsonc @@ -0,0 +1,204 @@ +// === findAllReferences === +// === /types.d.ts === +// declare namespace JSX { +// interface IntrinsicElements { +// 'my-el': { +// <|'[|{| isWriteAccess: true |}__prop:foo|]': string;|> +// }; +// } +// } + +// === /a.tsx === +// /> + + // === Definitions === + // === /types.d.ts === + // declare namespace JSX { + // interface IntrinsicElements { + // 'my-el': { + // <|'[|__prop:foo|]': string;|> + // }; + // } + // } + + // === Details === + [ + { + "containerKind": "", + "containerName": "", + "kind": "property", + "name": "(property) '__prop:foo': string", + "displayParts": [ + { + "text": "(", + "kind": "punctuation" + }, + { + "text": "property", + "kind": "text" + }, + { + "text": ")", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "'__prop:foo'", + "kind": "propertyName" + }, + { + "text": ":", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "string", + "kind": "keyword" + } + ] + } + ] + + + +// === findAllReferences === +// === /types.d.ts === +// declare namespace JSX { +// interface IntrinsicElements { +// 'my-el': { +// <|'[|{| isWriteAccess: true |}__prop:foo|]': string;|> +// }; +// } +// } + +// === /a.tsx === +// /> + + // === Definitions === + // === /types.d.ts === + // declare namespace JSX { + // interface IntrinsicElements { + // 'my-el': { + // <|'[|__prop:foo|]': string;|> + // }; + // } + // } + + // === Details === + [ + { + "containerKind": "", + "containerName": "", + "kind": "property", + "name": "(property) '__prop:foo': string", + "displayParts": [ + { + "text": "(", + "kind": "punctuation" + }, + { + "text": "property", + "kind": "text" + }, + { + "text": ")", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "'__prop:foo'", + "kind": "propertyName" + }, + { + "text": ":", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "string", + "kind": "keyword" + } + ] + } + ] + + + +// === findAllReferences === +// === /types.d.ts === +// declare namespace JSX { +// interface IntrinsicElements { +// 'my-el': { +// <|'/*FIND ALL REFS*/[|{| isWriteAccess: true, isDefinition: true |}__prop:foo|]': string;|> +// }; +// } +// } + +// === /a.tsx === +// /> + + // === Definitions === + // === /types.d.ts === + // declare namespace JSX { + // interface IntrinsicElements { + // 'my-el': { + // <|'/*FIND ALL REFS*/[|__prop:foo|]': string;|> + // }; + // } + // } + + // === Details === + [ + { + "containerKind": "", + "containerName": "", + "kind": "property", + "name": "(property) '__prop:foo': string", + "displayParts": [ + { + "text": "(", + "kind": "punctuation" + }, + { + "text": "property", + "kind": "text" + }, + { + "text": ")", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "'__prop:foo'", + "kind": "propertyName" + }, + { + "text": ":", + "kind": "punctuation" + }, + { + "text": " ", + "kind": "space" + }, + { + "text": "string", + "kind": "keyword" + } + ] + } + ] \ No newline at end of file diff --git a/tests/baselines/reference/renameOnJsxNamespacedName1.baseline.jsonc b/tests/baselines/reference/renameOnJsxNamespacedName1.baseline.jsonc new file mode 100644 index 0000000000000..693cba71eeed6 --- /dev/null +++ b/tests/baselines/reference/renameOnJsxNamespacedName1.baseline.jsonc @@ -0,0 +1,42 @@ +// === findRenameLocations === +// === /types.d.ts === +// declare namespace JSX { +// interface IntrinsicElements { +// 'my-el': { +// <|'[|prop:fooRENAME|]': string;|> +// }; +// } +// } + +// === /a.tsx === +// /> + + + +// === findRenameLocations === +// === /types.d.ts === +// declare namespace JSX { +// interface IntrinsicElements { +// 'my-el': { +// <|'[|prop:fooRENAME|]': string;|> +// }; +// } +// } + +// === /a.tsx === +// /> + + + +// === findRenameLocations === +// === /types.d.ts === +// declare namespace JSX { +// interface IntrinsicElements { +// 'my-el': { +// <|'[|prop:fooRENAME|]/*RENAME*/': string;|> +// }; +// } +// } + +// === /a.tsx === +// /> \ No newline at end of file diff --git a/tests/baselines/reference/renameOnJsxNamespacedName2.baseline.jsonc b/tests/baselines/reference/renameOnJsxNamespacedName2.baseline.jsonc new file mode 100644 index 0000000000000..92e346379d33e --- /dev/null +++ b/tests/baselines/reference/renameOnJsxNamespacedName2.baseline.jsonc @@ -0,0 +1,42 @@ +// === findRenameLocations === +// === /types.d.ts === +// declare namespace JSX { +// interface IntrinsicElements { +// 'my-el': { +// <|'[|__prop:fooRENAME|]': string;|> +// }; +// } +// } + +// === /a.tsx === +// /> + + + +// === findRenameLocations === +// === /types.d.ts === +// declare namespace JSX { +// interface IntrinsicElements { +// 'my-el': { +// <|'[|__prop:fooRENAME|]': string;|> +// }; +// } +// } + +// === /a.tsx === +// /> + + + +// === findRenameLocations === +// === /types.d.ts === +// declare namespace JSX { +// interface IntrinsicElements { +// 'my-el': { +// <|'[|__prop:fooRENAME|]/*RENAME*/': string;|> +// }; +// } +// } + +// === /a.tsx === +// /> \ No newline at end of file diff --git a/tests/cases/fourslash/findAllReferencesOnJsxNamespacedName1.ts b/tests/cases/fourslash/findAllReferencesOnJsxNamespacedName1.ts new file mode 100644 index 0000000000000..9cbe580009633 --- /dev/null +++ b/tests/cases/fourslash/findAllReferencesOnJsxNamespacedName1.ts @@ -0,0 +1,19 @@ +/// + +// @jsx: react + +// https://github.com/microsoft/TypeScript/issues/61820 + +// @Filename: /types.d.ts +//// declare namespace JSX { +//// interface IntrinsicElements { +//// 'my-el': { +//// '/*3*/prop:foo': string; +//// }; +//// } +//// } + +// @filename: /a.tsx +//// + +verify.baselineFindAllReferences("1", "2", "3"); diff --git a/tests/cases/fourslash/findAllReferencesOnJsxNamespacedName2.ts b/tests/cases/fourslash/findAllReferencesOnJsxNamespacedName2.ts new file mode 100644 index 0000000000000..ffb3c0eb7880d --- /dev/null +++ b/tests/cases/fourslash/findAllReferencesOnJsxNamespacedName2.ts @@ -0,0 +1,17 @@ +/// + +// @jsx: react + +// @Filename: /types.d.ts +//// declare namespace JSX { +//// interface IntrinsicElements { +//// 'my-el': { +//// '/*3*/__prop:foo': string; +//// }; +//// } +//// } + +// @filename: /a.tsx +//// + +verify.baselineFindAllReferences("1", "2", "3"); diff --git a/tests/cases/fourslash/renameOnJsxNamespacedName1.ts b/tests/cases/fourslash/renameOnJsxNamespacedName1.ts new file mode 100644 index 0000000000000..fd20e87f88398 --- /dev/null +++ b/tests/cases/fourslash/renameOnJsxNamespacedName1.ts @@ -0,0 +1,21 @@ +/// + +// @jsx: react + +// https://github.com/microsoft/TypeScript/issues/61820 + +// @Filename: /types.d.ts +//// declare namespace JSX { +//// interface IntrinsicElements { +//// 'my-el': { +//// 'prop:foo/*3*/': string; +//// }; +//// } +//// } + +// @filename: /a.tsx +//// + +verify.baselineRename("1"); +verify.baselineRename("2"); +verify.baselineRename("3"); diff --git a/tests/cases/fourslash/renameOnJsxNamespacedName2.ts b/tests/cases/fourslash/renameOnJsxNamespacedName2.ts new file mode 100644 index 0000000000000..49c3640512fc6 --- /dev/null +++ b/tests/cases/fourslash/renameOnJsxNamespacedName2.ts @@ -0,0 +1,21 @@ +/// + +// @jsx: react + +// https://github.com/microsoft/TypeScript/issues/61820 + +// @Filename: /types.d.ts +//// declare namespace JSX { +//// interface IntrinsicElements { +//// 'my-el': { +//// '__prop:foo/*3*/': string; +//// }; +//// } +//// } + +// @filename: /a.tsx +//// + +verify.baselineRename("1"); +verify.baselineRename("2"); +verify.baselineRename("3");