@seed-design/codemod 0.0.0-alpha-20241018093322
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.
- package/README.md +1 -0
- package/bin/index.mjs +7 -0
- package/package.json +39 -0
- package/src/index.ts +34 -0
- package/src/scripts/create-identifier-map.mjs +41 -0
- package/src/scripts/data.tsv +198 -0
- package/src/scripts/identifier-map.json.log +578 -0
- package/src/transforms/migrate-icons.ts +80 -0
- package/src/transforms/tests/migrate-icons.test.ts +409 -0
- package/src/utils/identifier-map.ts +580 -0
- package/src/utils/log.ts +20 -0
- package/src/utils/replace-node.ts +147 -0
@@ -0,0 +1,409 @@
|
|
1
|
+
import migrateIcons from "../migrate-icons.js";
|
2
|
+
import type { MigrateIconsOptions } from "../migrate-icons.js";
|
3
|
+
import { describe, expect, test } from "vitest";
|
4
|
+
import { applyTransform } from "jscodeshift/src/testUtils.js";
|
5
|
+
|
6
|
+
const testMatch: MigrateIconsOptions["match"] = {
|
7
|
+
source: [
|
8
|
+
{ startsWith: "@seed-design/icon", replaceWith: "@seed-design/react-icon" },
|
9
|
+
{ startsWith: "@seed-design/react-icon" },
|
10
|
+
],
|
11
|
+
identifier: {
|
12
|
+
OldIcon1Thin: "NewIcon1Line",
|
13
|
+
OldIcon1Regular: "NewIcon1Line",
|
14
|
+
OldIcon1Fill: "NewIcon1Fill",
|
15
|
+
|
16
|
+
OldIcon2Thin: "NewIcon2Line",
|
17
|
+
OldIcon2Regular: "NewIcon2Line",
|
18
|
+
OldIcon2Fill: "NewIcon2Fill",
|
19
|
+
|
20
|
+
OldIcon3Thin: "NewIcon3Line",
|
21
|
+
OldIcon3Regular: "NewIcon3Line",
|
22
|
+
OldIcon3Fill: "NewIcon3Fill",
|
23
|
+
|
24
|
+
OldIcon4Thin: "NewIcon4Line",
|
25
|
+
OldIcon4Regular: "NewIcon4Line",
|
26
|
+
OldIcon4Fill: "NewIcon4Fill",
|
27
|
+
|
28
|
+
OldIcon5Thin: "NewIcon5Line",
|
29
|
+
OldIcon5Regular: "NewIcon5Line",
|
30
|
+
OldIcon5Fill: "NewIcon5Fill",
|
31
|
+
|
32
|
+
OldIcon6Thin: "NewIcon6Line",
|
33
|
+
OldIcon6Regular: "NewIcon6Line",
|
34
|
+
OldIcon6Fill: "NewIcon6Fill",
|
35
|
+
|
36
|
+
OldIcon7Thin: "NewIcon7Line",
|
37
|
+
OldIcon7Regular: "NewIcon7Line",
|
38
|
+
OldIcon7Fill: "NewIcon7Fill",
|
39
|
+
|
40
|
+
OldIcon8Thin: "NewIcon8Line",
|
41
|
+
OldIcon8Regular: "NewIcon8Line",
|
42
|
+
OldIcon8Fill: "NewIcon8Fill",
|
43
|
+
|
44
|
+
OldIcon9Thin: "NewIcon9Line",
|
45
|
+
OldIcon9Regular: "NewIcon9Line",
|
46
|
+
OldIcon9Fill: "NewIcon9Fill",
|
47
|
+
},
|
48
|
+
};
|
49
|
+
|
50
|
+
function applyMigrateIconsTransform(source: string) {
|
51
|
+
const transformResult = applyTransform(
|
52
|
+
migrateIcons,
|
53
|
+
{ match: testMatch },
|
54
|
+
{ path: "path/to/file", source },
|
55
|
+
{ parser: "tsx" },
|
56
|
+
);
|
57
|
+
|
58
|
+
return transformResult;
|
59
|
+
}
|
60
|
+
|
61
|
+
describe("어떤 변경도 일어나면 안 되는 경우", () => {
|
62
|
+
test("import 없음", () => {
|
63
|
+
const input = `console.log("Hello, world!", OldIcon1Thin);`;
|
64
|
+
|
65
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(
|
66
|
+
`"console.log("Hello, world!", OldIcon1Thin);"`,
|
67
|
+
);
|
68
|
+
});
|
69
|
+
|
70
|
+
test("모든 import source match되지 않음", () => {
|
71
|
+
const input = `import { OldIcon1Thin, OldIcon2Thin } from "unrelated-package";
|
72
|
+
import { OldIcon3Thin as Icon3Alias } from "another-unrelated-package";
|
73
|
+
import OldIcon4Thin from "yet-another-unrelated-package/OldIcon4Thin";
|
74
|
+
import * as Icons from "yet-another-unrelated-package";
|
75
|
+
|
76
|
+
console.log(OldIcon1Thin);
|
77
|
+
|
78
|
+
function test() {
|
79
|
+
return <OldIcon2Thin />;
|
80
|
+
}
|
81
|
+
`;
|
82
|
+
|
83
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(`
|
84
|
+
"import { OldIcon1Thin, OldIcon2Thin } from "unrelated-package";
|
85
|
+
import { OldIcon3Thin as Icon3Alias } from "another-unrelated-package";
|
86
|
+
import OldIcon4Thin from "yet-another-unrelated-package/OldIcon4Thin";
|
87
|
+
import * as Icons from "yet-another-unrelated-package";
|
88
|
+
|
89
|
+
console.log(OldIcon1Thin);
|
90
|
+
|
91
|
+
function test() {
|
92
|
+
return <OldIcon2Thin />;
|
93
|
+
}"
|
94
|
+
`);
|
95
|
+
});
|
96
|
+
|
97
|
+
test("import source match 있지만 변경할 필요 없고, importSpecifier length 0 (unlikely)", () => {
|
98
|
+
const input = `import "@seed-design/react-icon";`;
|
99
|
+
|
100
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(
|
101
|
+
`"import "@seed-design/react-icon";"`,
|
102
|
+
);
|
103
|
+
});
|
104
|
+
|
105
|
+
test("import source match 있지만 변경할 필요 없고, importSpecifier length 1+지만 match 없음 (unlikely)", () => {
|
106
|
+
const input = `import { IconNotMatched } from "@seed-design/react-icon";
|
107
|
+
import { IconNotMatched2 as IconNotMatched2Alias } from "@seed-design/react-icon";
|
108
|
+
import type { IconType } from "@seed-design/react-icon";
|
109
|
+
import { type IconType2 } from "@seed-design/react-icon";
|
110
|
+
`;
|
111
|
+
|
112
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(`
|
113
|
+
"import { IconNotMatched } from "@seed-design/react-icon";
|
114
|
+
import { IconNotMatched2 as IconNotMatched2Alias } from "@seed-design/react-icon";
|
115
|
+
import type { IconType } from "@seed-design/react-icon";
|
116
|
+
import { type IconType2 } from "@seed-design/react-icon";"
|
117
|
+
`);
|
118
|
+
});
|
119
|
+
});
|
120
|
+
|
121
|
+
describe("importDeclaration: import source에만 변경 있는 경우", () => {
|
122
|
+
test("패키지명 변경 필요 있지만, importSpecifier length 0 (unlikely)", () => {
|
123
|
+
const input = `import "@seed-design/icon";`;
|
124
|
+
|
125
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(
|
126
|
+
`"import "@seed-design/react-icon";"`,
|
127
|
+
);
|
128
|
+
});
|
129
|
+
|
130
|
+
test("패키지명 변경 필요 있지만, importSpecifier length 0 (첫 줄에 주석 있음, unlikely)", () => {
|
131
|
+
const input = `// some comment
|
132
|
+
import "@seed-design/icon";
|
133
|
+
`;
|
134
|
+
|
135
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(`
|
136
|
+
"// some comment
|
137
|
+
import "@seed-design/react-icon";"
|
138
|
+
`);
|
139
|
+
});
|
140
|
+
|
141
|
+
test("패키지명 변경 필요 있고, importSpecifier length 1+지만 match 없음 (unlikely)", () => {
|
142
|
+
const input = `import { IconNotMatched } from "@seed-design/icon";
|
143
|
+
import { IconNotMatched2 as IconNotMatched2Alias } from "@seed-design/icon";
|
144
|
+
import type { IconType } from "@seed-design/icon";
|
145
|
+
import { type IconType2 } from "@seed-design/icon";
|
146
|
+
`;
|
147
|
+
|
148
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(`
|
149
|
+
"import { IconNotMatched } from "@seed-design/react-icon";
|
150
|
+
import { IconNotMatched2 as IconNotMatched2Alias } from "@seed-design/react-icon";
|
151
|
+
import type { IconType } from "@seed-design/react-icon";
|
152
|
+
import { type IconType2 } from "@seed-design/react-icon";"
|
153
|
+
`);
|
154
|
+
});
|
155
|
+
|
156
|
+
test("패키지명 변경 필요 있고, importDefaultSpecifier에 사용된 local specifier가 identifier와 match 없음 (deep import, unlikely)", () => {
|
157
|
+
const input = `import IconNotMatched from "@seed-design/icon/IconNotMatched";
|
158
|
+
import IconNotMatched2 from "@seed-design/icon/dist/lib/test/somewhat/IconNotMatched2";`;
|
159
|
+
|
160
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(`
|
161
|
+
"import IconNotMatched from "@seed-design/react-icon/IconNotMatched";
|
162
|
+
import IconNotMatched2 from "@seed-design/react-icon/dist/lib/test/somewhat/IconNotMatched2";"
|
163
|
+
`);
|
164
|
+
});
|
165
|
+
|
166
|
+
test("패키지명 변경 필요 없지만 하위 경로 변경 필요하고, importDefaultSpecifier에 사용된 local specifier가 identifier와 match 없음 (deep import, unlikely)", () => {
|
167
|
+
const input = `import IconNotMatched from "@seed-design/react-icon/OldIcon3Thin";`;
|
168
|
+
|
169
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(
|
170
|
+
`"import IconNotMatched from "@seed-design/react-icon/NewIcon3Line";"`,
|
171
|
+
);
|
172
|
+
});
|
173
|
+
|
174
|
+
test("패키지명 변경 필요 있지만 importNamespaceSpecifier", () => {
|
175
|
+
const input = `import * as Icons from "@seed-design/icon";`;
|
176
|
+
|
177
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(
|
178
|
+
`"import * as Icons from "@seed-design/react-icon";"`,
|
179
|
+
);
|
180
|
+
});
|
181
|
+
});
|
182
|
+
|
183
|
+
describe("importDeclaration: import source와 specifier 모두 변경 있는 경우", () => {
|
184
|
+
test("[가장 일반적] 패키지명에 변경 필요하고, specifier match 있음", () => {
|
185
|
+
const input = `import { OldIcon1Thin, OldIcon2Thin } from "@seed-design/icon";
|
186
|
+
import { OldIcon3Thin as Icon3Alias } from "@seed-design/icon";
|
187
|
+
import { OldIcon4Thin } from "@seed-design/icon";`;
|
188
|
+
|
189
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(`
|
190
|
+
"import { NewIcon1Line, NewIcon2Line } from "@seed-design/react-icon";
|
191
|
+
import { NewIcon3Line as Icon3Alias } from "@seed-design/react-icon";
|
192
|
+
import { NewIcon4Line } from "@seed-design/react-icon";"
|
193
|
+
`);
|
194
|
+
});
|
195
|
+
|
196
|
+
test("[가장 일반적] 패키지명에 변경 필요하고, importDefaultSpecifier이지만, 사용된 local specifier가 identifier와 match 있는 경우 (deep import)", () => {
|
197
|
+
const input = `import OldIcon1Thin from "@seed-design/icon/OldIcon1Thin";
|
198
|
+
import OldIcon2Thin from "@seed-design/icon/dist/lib/test/somewhat/OldIcon2Thin";`;
|
199
|
+
|
200
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(`
|
201
|
+
"import NewIcon1Line from "@seed-design/react-icon/NewIcon1Line";
|
202
|
+
import NewIcon2Line from "@seed-design/react-icon/dist/lib/test/somewhat/NewIcon2Line";"
|
203
|
+
`);
|
204
|
+
});
|
205
|
+
|
206
|
+
test("[가장 일반적] 패키지명 변경 필요 없지만 deep import라 하위 경로 변경 필요하고, importDefaultSpecifier에 사용된 local specifier가 identifier와 match 있는 경우 (deep import)", () => {
|
207
|
+
const input = `import OldIcon3Thin from "@seed-design/react-icon/OldIcon3Thin";`;
|
208
|
+
|
209
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(
|
210
|
+
`"import NewIcon3Line from "@seed-design/react-icon/NewIcon3Line";"`,
|
211
|
+
);
|
212
|
+
});
|
213
|
+
});
|
214
|
+
|
215
|
+
describe("importDeclaration: import specifier에만 변경 있는 경우", () => {
|
216
|
+
test("[가장 일반적] 패키지명 변경할 필요 없지만, specifier match 있음", () => {
|
217
|
+
const input = `import { OldIcon3Thin } from "@seed-design/react-icon";`;
|
218
|
+
|
219
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(
|
220
|
+
`"import { NewIcon3Line } from "@seed-design/react-icon";"`,
|
221
|
+
);
|
222
|
+
});
|
223
|
+
|
224
|
+
// deep import인 경우 import source만 변경되거나, import source와 specifier 모두 변경되어야 함
|
225
|
+
});
|
226
|
+
|
227
|
+
describe("identifiers: identifier 변경까지 있는 경우", () => {
|
228
|
+
test("source match와 identifier match 있는 경우", () => {
|
229
|
+
const input = `import { OldIcon1Thin, OldIcon2Thin } from "@seed-design/icon";
|
230
|
+
|
231
|
+
console.log(OldIcon1Thin);
|
232
|
+
|
233
|
+
return OldIcon2Thin;`;
|
234
|
+
|
235
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(`
|
236
|
+
"import { NewIcon1Line, NewIcon2Line } from "@seed-design/react-icon";
|
237
|
+
|
238
|
+
console.log(NewIcon1Line);
|
239
|
+
|
240
|
+
return NewIcon2Line;"
|
241
|
+
`);
|
242
|
+
});
|
243
|
+
|
244
|
+
test("source match와 identifier match 있는 경우 (jsx)", () => {
|
245
|
+
const input = `import { OldIcon1Thin, OldIcon2Thin } from "@seed-design/icon";
|
246
|
+
import { OldIcon3Thin as Icon3Alias } from "@seed-design/icon";
|
247
|
+
|
248
|
+
console.log(OldIcon1Thin);
|
249
|
+
|
250
|
+
function test() {
|
251
|
+
return <div>
|
252
|
+
<OldIcon2Thin />
|
253
|
+
<Icon3Alias />
|
254
|
+
</div>;
|
255
|
+
}`;
|
256
|
+
|
257
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(`
|
258
|
+
"import { NewIcon1Line, NewIcon2Line } from "@seed-design/react-icon";
|
259
|
+
import { NewIcon3Line as Icon3Alias } from "@seed-design/react-icon";
|
260
|
+
|
261
|
+
console.log(NewIcon1Line);
|
262
|
+
|
263
|
+
function test() {
|
264
|
+
return (
|
265
|
+
<div>
|
266
|
+
<NewIcon2Line />
|
267
|
+
<Icon3Alias />
|
268
|
+
</div>
|
269
|
+
);
|
270
|
+
}"
|
271
|
+
`);
|
272
|
+
});
|
273
|
+
|
274
|
+
test("source match와 identifier match 있는 경우 (jsx, 첫 줄에 주석 있음)", () => {
|
275
|
+
const input = `// some comment
|
276
|
+
|
277
|
+
import { OldIcon1Thin, OldIcon2Thin } from "@seed-design/icon";
|
278
|
+
import { OldIcon3Thin as Icon3Alias } from "@seed-design/icon";
|
279
|
+
|
280
|
+
console.log(OldIcon1Thin);
|
281
|
+
|
282
|
+
function test() {
|
283
|
+
return (<div>
|
284
|
+
<OldIcon2Thin />
|
285
|
+
<Icon3Alias />
|
286
|
+
</div>);
|
287
|
+
}`;
|
288
|
+
|
289
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(`
|
290
|
+
"// some comment
|
291
|
+
|
292
|
+
import { NewIcon1Line, NewIcon2Line } from "@seed-design/react-icon";
|
293
|
+
import { NewIcon3Line as Icon3Alias } from "@seed-design/react-icon";
|
294
|
+
|
295
|
+
console.log(NewIcon1Line);
|
296
|
+
|
297
|
+
function test() {
|
298
|
+
return (
|
299
|
+
(<div>
|
300
|
+
<NewIcon2Line />
|
301
|
+
<Icon3Alias />
|
302
|
+
</div>)
|
303
|
+
);
|
304
|
+
}"
|
305
|
+
`);
|
306
|
+
});
|
307
|
+
|
308
|
+
test("source match와 identifier match 있는 경우 (jsx, 첫 줄에 directive 있음)", () => {
|
309
|
+
const input = `"use client";
|
310
|
+
|
311
|
+
import { OldIcon1Thin, OldIcon2Thin } from "@seed-design/icon";
|
312
|
+
import { OldIcon3Thin as Icon3Alias } from "@seed-design/icon";
|
313
|
+
|
314
|
+
console.log(OldIcon1Thin);
|
315
|
+
|
316
|
+
function test() {
|
317
|
+
return (<div>
|
318
|
+
<OldIcon2Thin />
|
319
|
+
<Icon3Alias />
|
320
|
+
</div>);
|
321
|
+
}`;
|
322
|
+
|
323
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(`
|
324
|
+
""use client";
|
325
|
+
|
326
|
+
import { NewIcon1Line, NewIcon2Line } from "@seed-design/react-icon";
|
327
|
+
import { NewIcon3Line as Icon3Alias } from "@seed-design/react-icon";
|
328
|
+
|
329
|
+
console.log(NewIcon1Line);
|
330
|
+
|
331
|
+
function test() {
|
332
|
+
return (
|
333
|
+
(<div>
|
334
|
+
<NewIcon2Line />
|
335
|
+
<Icon3Alias />
|
336
|
+
</div>)
|
337
|
+
);
|
338
|
+
}"
|
339
|
+
`);
|
340
|
+
});
|
341
|
+
|
342
|
+
test("패키지명 변경 필요하고, importNamespaceSpecifier", () => {
|
343
|
+
const input = `import * as Icons from "@seed-design/icon";
|
344
|
+
|
345
|
+
console.log(Icons.OldIcon1Thin);`;
|
346
|
+
|
347
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(`
|
348
|
+
"import * as Icons from "@seed-design/react-icon";
|
349
|
+
|
350
|
+
console.log(Icons.NewIcon1Line);"
|
351
|
+
`);
|
352
|
+
});
|
353
|
+
});
|
354
|
+
|
355
|
+
describe("identifiers: identifier 변경만 있는 경우", () => {
|
356
|
+
test("패키지명 변경 필요 없고, importNamespaceSpecifier", () => {
|
357
|
+
const input = `import * as Icons from "@seed-design/react-icon";
|
358
|
+
|
359
|
+
console.log(Icons.OldIcon1Thin);`;
|
360
|
+
|
361
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(`
|
362
|
+
"import * as Icons from "@seed-design/react-icon";
|
363
|
+
|
364
|
+
console.log(Icons.NewIcon1Line);"
|
365
|
+
`);
|
366
|
+
});
|
367
|
+
});
|
368
|
+
|
369
|
+
describe("n:1 매핑", () => {
|
370
|
+
test("n:1 매핑", () => {
|
371
|
+
const input = `import { OldIcon1Thin, OldIcon1Regular, OldIcon1Fill } from "@seed-design/icon";`;
|
372
|
+
|
373
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(
|
374
|
+
`"import { NewIcon1Line, NewIcon1Fill } from "@seed-design/react-icon";"`,
|
375
|
+
);
|
376
|
+
});
|
377
|
+
|
378
|
+
test("n:1 매핑 with identifiers", () => {
|
379
|
+
const input = `import { OldIcon1Thin, OldIcon1Regular, OldIcon1Fill, OldIcon2Thin, OldIcon2Regular, OldIcon3Fill } from "@seed-design/icon";
|
380
|
+
|
381
|
+
console.log(OldIcon1Thin);
|
382
|
+
|
383
|
+
function test() {
|
384
|
+
return (<div>
|
385
|
+
<OldIcon1Regular />
|
386
|
+
<OldIcon1Thin />
|
387
|
+
<OldIcon3Fill />
|
388
|
+
<OldIcon2Thin />
|
389
|
+
</div>);
|
390
|
+
}`;
|
391
|
+
|
392
|
+
expect(applyMigrateIconsTransform(input)).toMatchInlineSnapshot(`
|
393
|
+
"import { NewIcon1Line, NewIcon1Fill, NewIcon2Line, NewIcon3Fill } from "@seed-design/react-icon";
|
394
|
+
|
395
|
+
console.log(NewIcon1Line);
|
396
|
+
|
397
|
+
function test() {
|
398
|
+
return (
|
399
|
+
(<div>
|
400
|
+
<NewIcon1Line />
|
401
|
+
<NewIcon1Line />
|
402
|
+
<NewIcon3Fill />
|
403
|
+
<NewIcon2Line />
|
404
|
+
</div>)
|
405
|
+
);
|
406
|
+
}"
|
407
|
+
`);
|
408
|
+
});
|
409
|
+
});
|