Skip to content

Commit 83b5e99

Browse files
committed
fix: fix rename bug
1 parent 9580878 commit 83b5e99

3 files changed

Lines changed: 54 additions & 30 deletions

File tree

packages/core/src/dts-generator.ts

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ interface GenerateDtsResult {
3838
text: string;
3939
mapping: CodeMapping;
4040
linkedCodeMapping: LinkedCodeMapping;
41+
/** Additional mappings used by ts-plugin (e.g. quoted string literal keys). */
42+
extraMappings?: CodeMapping[];
4143
}
4244

4345
/**
@@ -113,7 +115,7 @@ function generateNamedExportsDts(
113115
localTokens: Token[],
114116
tokenImporters: TokenImporter[],
115117
options: GenerateDtsOptions,
116-
): { text: string; mapping: CodeMapping; linkedCodeMapping: LinkedCodeMapping } {
118+
): GenerateDtsResult {
117119
const mapping: CodeMapping = { sourceOffsets: [], lengths: [], generatedOffsets: [] };
118120
const linkedCodeMapping: LinkedCodeMapping = {
119121
sourceOffsets: [],
@@ -263,11 +265,10 @@ function generateNamedExportsDts(
263265
}
264266

265267
/** Generate a d.ts file with a default export. */
266-
function generateDefaultExportDts(
267-
localTokens: Token[],
268-
tokenImporters: TokenImporter[],
269-
): { text: string; mapping: CodeMapping; linkedCodeMapping: LinkedCodeMapping } {
268+
function generateDefaultExportDts(localTokens: Token[], tokenImporters: TokenImporter[]): GenerateDtsResult {
270269
const mapping: CodeMapping = { sourceOffsets: [], lengths: [], generatedOffsets: [], generatedLengths: [] };
270+
//
271+
const quotedMapping: CodeMapping = { sourceOffsets: [], lengths: [], generatedOffsets: [], generatedLengths: [] };
271272
const linkedCodeMapping: LinkedCodeMapping = {
272273
sourceOffsets: [],
273274
lengths: [],
@@ -326,16 +327,31 @@ function generateDefaultExportDts(
326327
*/
327328

328329
text += ` `;
329-
mapping.sourceOffsets.push(token.loc.start.offset);
330-
mapping.generatedOffsets.push(text.length);
331-
mapping.lengths.push(token.name.length);
332330
if (isValidAsJSIdentifier(token.name)) {
331+
mapping.sourceOffsets.push(token.loc.start.offset);
332+
mapping.lengths.push(token.name.length);
333+
mapping.generatedOffsets.push(text.length);
333334
mapping.generatedLengths!.push(token.name.length);
334335
text += `${token.name}: '' as readonly string,\n`;
335336
} else {
336-
// Include quotes in the mapping for invalid JS identifiers
337-
mapping.generatedLengths!.push(token.name.length + 2);
338-
text += `'${token.name}': '' as readonly string,\n`;
337+
const quoteStart = text.length;
338+
text += `'`;
339+
const keyStart = text.length;
340+
// Map unquoted range in the primary mapping.
341+
// This mapping is necessary when renaming.
342+
// When performing a rename, the textSpan does not include quotes,
343+
// but for "go to definition," the textSpan includes quotes, which necessitates a dual mapping.
344+
mapping.sourceOffsets.push(token.loc.start.offset);
345+
mapping.lengths.push(token.name.length);
346+
mapping.generatedOffsets.push(keyStart);
347+
mapping.generatedLengths!.push(token.name.length);
348+
// Map quoted range separately to avoid overlapping ranges in a single mapping.
349+
// This mapping is necessary for features like "go to definition".
350+
quotedMapping.sourceOffsets.push(token.loc.start.offset);
351+
quotedMapping.lengths.push(token.name.length);
352+
quotedMapping.generatedOffsets.push(quoteStart);
353+
quotedMapping.generatedLengths!.push(token.name.length + 2);
354+
text += `${token.name}': '' as readonly string,\n`;
339355
}
340356
}
341357
for (const tokenImporter of tokenImporters) {
@@ -438,6 +454,9 @@ function generateDefaultExportDts(
438454
}
439455
}
440456
text += `};\nexport default ${STYLES_EXPORT_NAME};\n`;
457+
if (quotedMapping.sourceOffsets.length) {
458+
return { text, mapping, linkedCodeMapping, extraMappings: [quotedMapping] };
459+
}
441460
return { text, mapping, linkedCodeMapping };
442461
}
443462

packages/ts-plugin/e2e-test/feature/rename-symbol.test.ts

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -387,23 +387,22 @@ describe('Rename Symbol', async () => {
387387
},
388388
],
389389
},
390-
// TODO
391-
// {
392-
// name: 'e-1 in index.ts',
393-
// file: iff.paths['index.ts'],
394-
// line: 9,
395-
// offset: 9,
396-
// expected: [
397-
// {
398-
// file: formatPath(iff.paths['index.ts']),
399-
// locs: [{ start: { line: 9, offset: 9 }, end: { line: 9, offset: 12 } }],
400-
// },
401-
// {
402-
// file: formatPath(iff.paths['a.module.css']),
403-
// locs: [{ start: { line: 6, offset: 2 }, end: { line: 6, offset: 5 } }],
404-
// },
405-
// ],
406-
// },
390+
{
391+
name: 'e-1 in index.ts',
392+
file: iff.paths['index.ts'],
393+
line: 9,
394+
offset: 9,
395+
expected: [
396+
{
397+
file: formatPath(iff.paths['index.ts']),
398+
locs: [{ start: { line: 9, offset: 9 }, end: { line: 9, offset: 12 } }],
399+
},
400+
{
401+
file: formatPath(iff.paths['a.module.css']),
402+
locs: [{ start: { line: 6, offset: 2 }, end: { line: 6, offset: 5 } }],
403+
},
404+
],
405+
},
407406
])('Rename Symbol for $name', async ({ file, line, offset, expected }) => {
408407
const res = await tsserver.sendRename({
409408
file,

packages/ts-plugin/src/language-plugin.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ export function createCSSLanguagePlugin(
5252
keyframes: config.keyframes,
5353
});
5454
// eslint-disable-next-line prefer-const
55-
let { text, mapping, linkedCodeMapping } = generateDts(cssModule, { ...config, forTsPlugin: true });
55+
let { text, mapping, linkedCodeMapping, extraMappings } = generateDts(cssModule, {
56+
...config,
57+
forTsPlugin: true,
58+
});
5659
return {
5760
id: 'main',
5861
languageId: 'typescript',
@@ -62,7 +65,10 @@ export function createCSSLanguagePlugin(
6265
getChangeRange: () => undefined,
6366
},
6467
// `mappings` are required to support "Go to Definition" and renaming
65-
mappings: [{ ...mapping, data: { navigation: true } }],
68+
mappings: [
69+
{ ...mapping, data: { navigation: true } },
70+
...(extraMappings?.map((m) => ({ ...m, data: { navigation: true } })) ?? []),
71+
],
6672
// `linkedCodeMappings` are required to support "Go to Definition" and renaming for the imported tokens
6773
linkedCodeMappings: [{ ...linkedCodeMapping, data: undefined }],
6874
[CMK_DATA_KEY]: cssModule,

0 commit comments

Comments
 (0)