@toss/tds-mobile-migration 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/cli.js +2 -0
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +43 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/tds-v2/codemod/commands/badge-props-rename.cjs +81 -0
  7. package/dist/tds-v2/codemod/commands/badge-size-rename.cjs +89 -0
  8. package/dist/tds-v2/codemod/commands/boardrow-rightarrow-rename.cjs +89 -0
  9. package/dist/tds-v2/codemod/commands/bottomcta-component-rename.cjs +70 -0
  10. package/dist/tds-v2/codemod/commands/button-export-rename.cjs +120 -0
  11. package/dist/tds-v2/codemod/commands/button-props-rename.cjs +205 -0
  12. package/dist/tds-v2/codemod/commands/button-size-rename.cjs +209 -0
  13. package/dist/tds-v2/codemod/commands/iconbutton-label-to-aria-label.cjs +84 -0
  14. package/dist/tds-v2/codemod/commands/listrow-verticalpadding-rename.cjs +101 -0
  15. package/dist/tds-v2/codemod/commands/textbutton-typography-to-size.cjs +229 -0
  16. package/dist/tds-v2/codemod/commands/top-subtitle-props-rename.cjs +66 -0
  17. package/dist/tds-v2/index.d.ts +2 -0
  18. package/dist/tds-v2/index.d.ts.map +1 -0
  19. package/dist/tds-v2/index.js +2 -0
  20. package/dist/tds-v2/index.js.map +1 -0
  21. package/dist/tds-v2/runCodemod.d.ts +5 -0
  22. package/dist/tds-v2/runCodemod.d.ts.map +1 -0
  23. package/dist/tds-v2/runCodemod.js +37 -0
  24. package/dist/tds-v2/runCodemod.js.map +1 -0
  25. package/dist/tsconfig.tsbuildinfo +1 -0
  26. package/dist/v2/codemod/commands/provider.cjs +97 -0
  27. package/dist/v2/index.d.ts +2 -0
  28. package/dist/v2/index.d.ts.map +1 -0
  29. package/dist/v2/index.js +2 -0
  30. package/dist/v2/index.js.map +1 -0
  31. package/dist/v2/runCodemod.d.ts +5 -0
  32. package/dist/v2/runCodemod.d.ts.map +1 -0
  33. package/dist/v2/runCodemod.js +37 -0
  34. package/dist/v2/runCodemod.js.map +1 -0
  35. package/package.json +23 -0
package/cli.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import './dist/cli.js';
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,43 @@
1
+ import chalk from 'chalk';
2
+ import { Command } from 'commander';
3
+ import { runCodemod as runMobileV2Codemod } from './tds-v2/index.js';
4
+ import { runCodemod as runMobileV2CodemodForAIT } from './v2/index.js';
5
+ const program = new Command();
6
+ const TDS_V2_BREAKING_CHANGE_COMPONENTS = [
7
+ 'textbutton-typography-to-size',
8
+ 'badge-props-rename',
9
+ 'top-subtitle-props-rename',
10
+ 'badge-size-rename',
11
+ 'boardrow-rightarrow-rename',
12
+ 'bottomcta-component-rename',
13
+ 'button-export-rename',
14
+ 'button-size-rename',
15
+ 'button-props-rename',
16
+ 'iconbutton-label-to-aria-label',
17
+ 'listrow-verticalpadding-rename',
18
+ ];
19
+ const AIT_CODEMODS = ['provider'];
20
+ program
21
+ .command('tds-v2 [destination]')
22
+ .option('-g --glob <glob>', 'Glob for files upon which to apply the migration', '{src,pages}/**/*.{ts,tsx}')
23
+ .action(async (_, { glob }) => {
24
+ try {
25
+ console.log(chalk.green('BC가 담긴 컴포넌트 마이그레이션을 진행해요'));
26
+ for (const component of TDS_V2_BREAKING_CHANGE_COMPONENTS) {
27
+ console.log(chalk.green(`BC Migration: ${component} 마이그레이션을 진행해요`));
28
+ await runMobileV2Codemod(component, { glob, packageName: '@toss/tds-mobile' });
29
+ }
30
+ for (const component of AIT_CODEMODS) {
31
+ console.log(chalk.green(`AIT Migration: ${component} 마이그레이션을 진행해요`));
32
+ await runMobileV2CodemodForAIT(component, { glob, packageName: '@toss/tds-mobile-ait' });
33
+ }
34
+ console.log(chalk.green('--------------------------------\n\n'));
35
+ console.log(chalk.green('v2 마이그레이션 작업들이 완료되었어요!'));
36
+ }
37
+ catch (error) {
38
+ console.error(error);
39
+ process.exit(1);
40
+ }
41
+ });
42
+ program.parse(process.argv);
43
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,IAAI,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACrE,OAAO,EAAE,UAAU,IAAI,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAEvE,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,MAAM,iCAAiC,GAAG;IACxC,+BAA+B;IAC/B,oBAAoB;IACpB,2BAA2B;IAC3B,mBAAmB;IACnB,4BAA4B;IAC5B,4BAA4B;IAC5B,sBAAsB;IACtB,oBAAoB;IACpB,qBAAqB;IACrB,gCAAgC;IAChC,gCAAgC;CACjC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,UAAU,CAAC,CAAC;AAElC,OAAO;KACJ,OAAO,CAAC,sBAAsB,CAAC;KAC/B,MAAM,CAAC,kBAAkB,EAAE,kDAAkD,EAAE,2BAA2B,CAAC;KAC3G,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,IAAI,EAAoB,EAAE,EAAE;IAC9C,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC,CAAC;QACrD,KAAK,MAAM,SAAS,IAAI,iCAAiC,EAAE,CAAC;YAC1D,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,iBAAiB,SAAS,eAAe,CAAC,CAAC,CAAC;YACpE,MAAM,kBAAkB,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,kBAAkB,EAAE,CAAC,CAAC;QACjF,CAAC;QAED,KAAK,MAAM,SAAS,IAAI,YAAY,EAAE,CAAC;YACrC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,kBAAkB,SAAS,eAAe,CAAC,CAAC,CAAC;YACrE,MAAM,wBAAwB,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,sBAAsB,EAAE,CAAC,CAAC;QAC3F,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC,CAAC;QAEjE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC,CAAC;IACrD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * @type {import('jscodeshift').Transform}
3
+ */
4
+ const transform = (fileInfo, { jscodeshift: j }, options) => {
5
+ const root = j(fileInfo.source);
6
+
7
+ // package name을 options에서 가져와요 (기본값: @tds/mobile)
8
+ const packageName = options['package-name'] || '@tds/mobile';
9
+
10
+ // packageName에서 import된 컴포넌트들을 추적하는 Set
11
+ const tdsImportedComponents = new Set();
12
+
13
+ // packageName import 구문들을 찾아서 컴포넌트 이름들을 수집해요
14
+ root
15
+ .find(j.ImportDeclaration, {
16
+ source: { value: packageName },
17
+ })
18
+ .forEach(path => {
19
+ path.value.specifiers.forEach(specifier => {
20
+ if (specifier.type === 'ImportSpecifier') {
21
+ tdsImportedComponents.add(specifier.local.name);
22
+ }
23
+ });
24
+ });
25
+
26
+ // Badge 관련 컴포넌트가 packageName에서 import되지 않았다면 변환하지 않아요
27
+ if (!tdsImportedComponents.has('Badge') && !tdsImportedComponents.has('Paragraph') && !tdsImportedComponents.has('Top')) {
28
+ return fileInfo.source;
29
+ }
30
+
31
+ // prop 이름 매핑 규칙
32
+ const propNameMap = {
33
+ type: 'color',
34
+ style: 'variant',
35
+ htmlStyle: 'style',
36
+ };
37
+
38
+ // JSX 컴포넌트의 prop 이름 변경 공통 함수
39
+ function transformPropNames(openingElement) {
40
+ const attributes = openingElement.attributes;
41
+
42
+ // 모든 속성을 순회하면서 매핑된 prop 이름 변경
43
+ attributes.forEach(attr => {
44
+ if (attr.type === 'JSXAttribute' && propNameMap[attr.name.name]) {
45
+ attr.name.name = propNameMap[attr.name.name];
46
+ }
47
+ });
48
+ }
49
+
50
+ // 모든 JSX 요소를 순회해요
51
+ root.find(j.JSXElement).forEach(path => {
52
+ const openingElement = path.value.openingElement;
53
+ const elementName = openingElement.name;
54
+
55
+ // Badge 직접 사용 - packageName에서 import된 경우에만
56
+ if (elementName.name === 'Badge' && tdsImportedComponents.has('Badge')) {
57
+ transformPropNames(openingElement);
58
+ }
59
+ // 컴파운드 컴포넌트들
60
+ else if (elementName.type === 'JSXMemberExpression') {
61
+ const objectName = elementName.object.name;
62
+ const propertyName = elementName.property.name;
63
+
64
+ // Paragraph.Badge - Paragraph가 packageName에서 import된 경우에만
65
+ if (objectName === 'Paragraph' && propertyName === 'Badge' && tdsImportedComponents.has('Paragraph')) {
66
+ transformPropNames(openingElement);
67
+ }
68
+ // Top.SubtitleBadges - Top이 packageName에서 import된 경우에만
69
+ else if (objectName === 'Top' && propertyName === 'SubtitleBadges' && tdsImportedComponents.has('Top')) {
70
+ transformPropNames(openingElement);
71
+ }
72
+ }
73
+ });
74
+
75
+ return root.toSource({ quote: 'double' });
76
+ };
77
+
78
+ const parser = 'tsx';
79
+
80
+ module.exports = transform;
81
+ module.exports.parser = parser;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * @type {import('jscodeshift').Transform}
3
+ */
4
+ const transform = (fileInfo, { jscodeshift: j }, options) => {
5
+ const root = j(fileInfo.source);
6
+
7
+ // package name을 options에서 가져와요 (기본값: @tds/mobile)
8
+ const packageName = options['package-name'] || '@tds/mobile';
9
+
10
+ // packageName에서 import된 컴포넌트들을 추적하는 Set
11
+ const tdsImportedComponents = new Set();
12
+
13
+ // packageName import 구문들을 찾아서 컴포넌트 이름들을 수집해요
14
+ root
15
+ .find(j.ImportDeclaration, {
16
+ source: { value: packageName },
17
+ })
18
+ .forEach(path => {
19
+ path.value.specifiers.forEach(specifier => {
20
+ if (specifier.type === 'ImportSpecifier') {
21
+ tdsImportedComponents.add(specifier.local.name);
22
+ }
23
+ });
24
+ });
25
+
26
+ // Badge 관련 컴포넌트가 packageName에서 import되지 않았다면 변환하지 않아요
27
+ if (!tdsImportedComponents.has('Badge') && !tdsImportedComponents.has('Paragraph') && !tdsImportedComponents.has('Top')) {
28
+ return fileInfo.source;
29
+ }
30
+
31
+ // size 값 매핑 규칙
32
+ const sizeValueMap = {
33
+ tiny: 'xsmall',
34
+ };
35
+
36
+ // JSX 컴포넌트의 size prop 값 변경 공통 함수
37
+ function transformSizeValues(openingElement) {
38
+ const attributes = openingElement.attributes;
39
+
40
+ // size 속성 찾아서 값 변경
41
+ attributes.forEach(attr => {
42
+ if (attr.type === 'JSXAttribute' && attr.name.name === 'size') {
43
+ let sizeValue = null;
44
+
45
+ // 속성 값 추출해요 - StringLiteral과 Literal 둘 다 처리
46
+ if (attr.value && (attr.value.type === 'Literal' || attr.value.type === 'StringLiteral')) {
47
+ sizeValue = attr.value.value;
48
+ }
49
+
50
+ // 매핑된 값이 있으면 변경해요
51
+ if (sizeValue && sizeValueMap[sizeValue]) {
52
+ attr.value.value = sizeValueMap[sizeValue];
53
+ }
54
+ }
55
+ });
56
+ }
57
+
58
+ // 모든 JSX 요소를 순회해요
59
+ root.find(j.JSXElement).forEach(path => {
60
+ const openingElement = path.value.openingElement;
61
+ const elementName = openingElement.name;
62
+
63
+ // Badge 직접 사용 - packageName에서 import된 경우에만
64
+ if (elementName.name === 'Badge' && tdsImportedComponents.has('Badge')) {
65
+ transformSizeValues(openingElement);
66
+ }
67
+ // 컴파운드 컴포넌트들
68
+ else if (elementName.type === 'JSXMemberExpression') {
69
+ const objectName = elementName.object.name;
70
+ const propertyName = elementName.property.name;
71
+
72
+ // Paragraph.Badge - Paragraph가 packageName에서 import된 경우에만
73
+ if (objectName === 'Paragraph' && propertyName === 'Badge' && tdsImportedComponents.has('Paragraph')) {
74
+ transformSizeValues(openingElement);
75
+ }
76
+ // Top.SubtitleBadges - Top이 packageName에서 import된 경우에만
77
+ else if (objectName === 'Top' && propertyName === 'SubtitleBadges' && tdsImportedComponents.has('Top')) {
78
+ transformSizeValues(openingElement);
79
+ }
80
+ }
81
+ });
82
+
83
+ return root.toSource({ quote: 'double' });
84
+ };
85
+
86
+ const parser = 'tsx';
87
+
88
+ module.exports = transform;
89
+ module.exports.parser = parser;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * @type {import('jscodeshift').Transform}
3
+ */
4
+ const transform = (fileInfo, { jscodeshift: j }, options) => {
5
+ const root = j(fileInfo.source);
6
+
7
+ // package name을 options에서 가져와요 (기본값: @tds/mobile)
8
+ const packageName = options['package-name'] || '@tds/mobile';
9
+
10
+ // packageName에서 import된 컴포넌트들을 추적하는 Set
11
+ const tdsImportedComponents = new Set();
12
+
13
+ // packageName import 구문들을 찾아서 컴포넌트 이름들을 수집해요
14
+ root
15
+ .find(j.ImportDeclaration, {
16
+ source: { value: packageName },
17
+ })
18
+ .forEach(path => {
19
+ path.value.specifiers.forEach(specifier => {
20
+ if (specifier.type === 'ImportSpecifier') {
21
+ tdsImportedComponents.add(specifier.local.name);
22
+ }
23
+ });
24
+ });
25
+
26
+ // BoardRow 컴포넌트가 packageName에서 import되지 않았다면 변환하지 않아요
27
+ if (!tdsImportedComponents.has('BoardRow')) {
28
+ return fileInfo.source;
29
+ }
30
+
31
+ // 1. JSX 컴포넌트 이름 변경: BoardRow.RightArrow → BoardRow.ArrowIcon
32
+ root.find(j.JSXElement).forEach(path => {
33
+ const openingElement = path.value.openingElement;
34
+ const closingElement = path.value.closingElement;
35
+
36
+ // JSXMemberExpression 체크 (BoardRow.RightArrow)
37
+ if (openingElement.name.type === 'JSXMemberExpression') {
38
+ const objectName = openingElement.name.object.name;
39
+ const propertyName = openingElement.name.property.name;
40
+
41
+ // BoardRow.RightArrow - BoardRow가 packageName에서 import된 경우에만
42
+ if (objectName === 'BoardRow' && propertyName === 'RightArrow' && tdsImportedComponents.has('BoardRow')) {
43
+ // opening element 변경
44
+ openingElement.name.property.name = 'ArrowIcon';
45
+
46
+ // closing element도 변경 (있는 경우)
47
+ if (closingElement && closingElement.name.type === 'JSXMemberExpression') {
48
+ closingElement.name.property.name = 'ArrowIcon';
49
+ }
50
+ }
51
+ }
52
+ });
53
+
54
+ // 2. TypeScript 타입 이름 변경: BoardRowRightArrowProps → BoardRowArrowIconProps
55
+ root.find(j.Identifier, { name: 'BoardRowRightArrowProps' }).forEach(path => {
56
+ path.node.name = 'BoardRowArrowIconProps';
57
+ });
58
+
59
+ // 3. TSTypeReference에서도 변경 (타입 참조에서)
60
+ root.find(j.TSTypeReference).forEach(path => {
61
+ if (path.node.typeName && path.node.typeName.name === 'BoardRowRightArrowProps') {
62
+ path.node.typeName.name = 'BoardRowArrowIconProps';
63
+ }
64
+ });
65
+
66
+ // 4. Import/Export에서도 변경
67
+ root.find(j.ImportSpecifier).forEach(path => {
68
+ if (path.node.imported.name === 'BoardRowRightArrowProps') {
69
+ path.node.imported.name = 'BoardRowArrowIconProps';
70
+ // local name도 같이 변경 (as로 rename 안한 경우)
71
+ if (path.node.local.name === 'BoardRowRightArrowProps') {
72
+ path.node.local.name = 'BoardRowArrowIconProps';
73
+ }
74
+ }
75
+ });
76
+
77
+ root.find(j.ExportSpecifier).forEach(path => {
78
+ if (path.node.exported.name === 'BoardRowRightArrowProps') {
79
+ path.node.exported.name = 'BoardRowArrowIconProps';
80
+ }
81
+ });
82
+
83
+ return root.toSource({ quote: 'double' });
84
+ };
85
+
86
+ const parser = 'tsx';
87
+
88
+ module.exports = transform;
89
+ module.exports.parser = parser;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @type {import('jscodeshift').Transform}
3
+ */
4
+ const transform = (fileInfo, { jscodeshift: j }, options) => {
5
+ const root = j(fileInfo.source);
6
+
7
+ // package name을 options에서 가져와요 (기본값: @tds/mobile)
8
+ const packageName = options['package-name'] || '@tds/mobile';
9
+
10
+ // packageName에서 import된 컴포넌트들을 추적하는 Set
11
+ const tdsImportedComponents = new Set();
12
+
13
+ // packageName import 구문들을 찾아서 컴포넌트 이름들을 수집해요
14
+ root
15
+ .find(j.ImportDeclaration, {
16
+ source: { value: packageName },
17
+ })
18
+ .forEach(path => {
19
+ path.value.specifiers.forEach(specifier => {
20
+ if (specifier.type === 'ImportSpecifier') {
21
+ tdsImportedComponents.add(specifier.local.name);
22
+ }
23
+ });
24
+ });
25
+
26
+ // BottomCTA 또는 FixedBottomCTA 컴포넌트가 packageName에서 import되지 않았다면 변환하지 않아요
27
+ if (!tdsImportedComponents.has('BottomCTA') && !tdsImportedComponents.has('FixedBottomCTA')) {
28
+ return fileInfo.source;
29
+ }
30
+
31
+ // 컴포넌트 이름 매핑 규칙
32
+ const componentNameMap = {
33
+ TypeA: 'Single',
34
+ TypeB: 'Double',
35
+ };
36
+
37
+ // 모든 JSX 요소를 순회해요
38
+ root.find(j.JSXElement).forEach(path => {
39
+ const openingElement = path.value.openingElement;
40
+ const closingElement = path.value.closingElement;
41
+
42
+ // 컴파운드 컴포넌트인지 확인해요 (BottomCTA.TypeA, BottomCTA.TypeB, FixedBottomCTA.TypeA, FixedBottomCTA.TypeB)
43
+ if (openingElement.name && openingElement.name.type === 'JSXMemberExpression') {
44
+ const objectName = openingElement.name.object.name;
45
+ const propertyName = openingElement.name.property.name;
46
+
47
+ // BottomCTA 또는 FixedBottomCTA 컴포넌트의 TypeA, TypeB인 경우에만 처리해요 - packageName에서 import된 경우에만
48
+ if (
49
+ (objectName === 'BottomCTA' || objectName === 'FixedBottomCTA') &&
50
+ componentNameMap[propertyName] &&
51
+ tdsImportedComponents.has(objectName)
52
+ ) {
53
+ // opening element 이름 변경해요
54
+ openingElement.name.property.name = componentNameMap[propertyName];
55
+
56
+ // closing element도 있으면 변경해요
57
+ if (closingElement && closingElement.name && closingElement.name.type === 'JSXMemberExpression') {
58
+ closingElement.name.property.name = componentNameMap[propertyName];
59
+ }
60
+ }
61
+ }
62
+ });
63
+
64
+ return root.toSource({ quote: 'single' });
65
+ };
66
+
67
+ const parser = 'tsx';
68
+
69
+ module.exports = transform;
70
+ module.exports.parser = parser;
@@ -0,0 +1,120 @@
1
+ /**
2
+ * @type {import('jscodeshift').Transform}
3
+ */
4
+ const transform = (fileInfo, { jscodeshift: j }, options) => {
5
+ const root = j(fileInfo.source);
6
+
7
+ // package name을 options에서 가져와요 (기본값: @tds/mobile)
8
+ const packageName = options['package-name'] || '@tds/mobile';
9
+
10
+ // packageName에서 import하는 export들을 추적하는 Set
11
+ const tdsImportedExports = new Set();
12
+
13
+ // export 이름 매핑 규칙
14
+ const exportNameMap = {
15
+ TDSButtonStyle: 'TDSButtonVariant',
16
+ TDSButtonType: 'TDSButtonColor',
17
+ };
18
+
19
+ const identifiersToRename = new Map();
20
+ let hasChanges = false;
21
+
22
+ // packageName에서 import하는 구문들을 찾아서 처리해요
23
+ root
24
+ .find(j.ImportDeclaration, {
25
+ source: { value: packageName },
26
+ })
27
+ .forEach(path => {
28
+ path.value.specifiers.forEach(specifier => {
29
+ if (specifier.type === 'ImportSpecifier') {
30
+ // named import 처리 (import { TDSButtonStyle, TDSButtonType } from packageName)
31
+ if (specifier.imported && specifier.imported.name) {
32
+ const importedName = specifier.imported.name;
33
+ const localName = specifier.local.name;
34
+
35
+ // export 이름을 Set에 추가해요
36
+ tdsImportedExports.add(importedName);
37
+
38
+ if (exportNameMap[importedName]) {
39
+ // import 시 이름 변경해요
40
+ specifier.imported.name = exportNameMap[importedName];
41
+
42
+ // alias가 없는 경우에만 local name도 변경하고 rename 대상에 추가해요
43
+ if (localName === importedName) {
44
+ specifier.local.name = exportNameMap[importedName];
45
+ // alias가 없는 경우에만 rename 대상으로 추가해요
46
+ identifiersToRename.set(localName, exportNameMap[importedName]);
47
+ }
48
+
49
+ hasChanges = true;
50
+ }
51
+ }
52
+ }
53
+ });
54
+ });
55
+
56
+ // type import도 처리해요 (import type { TDSButtonStyle } from packageName)
57
+ root
58
+ .find(j.ImportDeclaration, {
59
+ source: { value: packageName },
60
+ importKind: 'type',
61
+ })
62
+ .forEach(path => {
63
+ path.value.specifiers.forEach(specifier => {
64
+ if (specifier.type === 'ImportSpecifier' && specifier.imported && specifier.imported.name) {
65
+ const importedName = specifier.imported.name;
66
+ const localName = specifier.local.name;
67
+
68
+ // export 이름을 Set에 추가해요
69
+ tdsImportedExports.add(importedName);
70
+
71
+ if (exportNameMap[importedName]) {
72
+ specifier.imported.name = exportNameMap[importedName];
73
+
74
+ // alias가 없는 경우에만 local name도 변경하고 rename 대상에 추가해요
75
+ if (localName === importedName) {
76
+ specifier.local.name = exportNameMap[importedName];
77
+ // alias가 없는 경우에만 rename 대상으로 추가해요
78
+ identifiersToRename.set(localName, exportNameMap[importedName]);
79
+ }
80
+
81
+ hasChanges = true;
82
+ }
83
+ }
84
+ });
85
+ });
86
+
87
+ // Button 관련 export가 packageName에서 import되지 않았다면 변환하지 않아요
88
+ if (!tdsImportedExports.has('TDSButtonStyle') && !tdsImportedExports.has('TDSButtonType')) {
89
+ return fileInfo.source;
90
+ }
91
+
92
+ // import 외의 일반 코드에서 Button 관련 식별자 이름 변경 적용해요
93
+ identifiersToRename.forEach((newName, oldName) => {
94
+ root
95
+ .find(j.Identifier, { name: oldName })
96
+ .filter(path => {
97
+ // 이미 import 구문에서 처리된 경우 건너뛰어요
98
+ if (path.parent.value.type === 'ImportSpecifier') return false;
99
+ // 멤버 접근의 프로퍼티인 경우 건너뛰어요 (예: obj.TDSButtonStyle)
100
+ if (
101
+ path.parent.value.type === 'MemberExpression' &&
102
+ path.parent.value.property === path.node &&
103
+ !path.parent.value.computed
104
+ ) {
105
+ return false;
106
+ }
107
+ return true;
108
+ })
109
+ .forEach(path => {
110
+ path.node.name = newName;
111
+ });
112
+ });
113
+
114
+ return hasChanges ? root.toSource({ quote: 'double' }) : fileInfo.source;
115
+ };
116
+
117
+ const parser = 'tsx';
118
+
119
+ module.exports = transform;
120
+ module.exports.parser = parser;