@clerk/upgrade 2.0.0-snapshot.v20251204143242 → 2.0.0-snapshot.v20251208202852

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 (54) hide show
  1. package/dist/__tests__/fixtures/expo-old-package/package-lock.json +5 -0
  2. package/dist/__tests__/fixtures/expo-old-package/package.json +10 -0
  3. package/dist/__tests__/fixtures/expo-old-package/src/App.tsx +14 -0
  4. package/dist/__tests__/fixtures/nextjs-v6/package.json +9 -0
  5. package/dist/__tests__/fixtures/nextjs-v6/pnpm-lock.yaml +2 -0
  6. package/dist/__tests__/fixtures/nextjs-v6/src/app.tsx +17 -0
  7. package/dist/__tests__/fixtures/nextjs-v7/package.json +9 -0
  8. package/dist/__tests__/fixtures/nextjs-v7/pnpm-lock.yaml +2 -0
  9. package/dist/__tests__/fixtures/nextjs-v7/src/app.tsx +16 -0
  10. package/dist/__tests__/fixtures/no-clerk/package.json +7 -0
  11. package/dist/__tests__/fixtures/react-v6/package.json +8 -0
  12. package/dist/__tests__/fixtures/react-v6/src/App.tsx +19 -0
  13. package/dist/__tests__/fixtures/react-v6/yarn.lock +2 -0
  14. package/dist/__tests__/helpers/create-fixture.js +56 -0
  15. package/dist/__tests__/integration/cli.test.js +230 -0
  16. package/dist/__tests__/integration/config.test.js +76 -0
  17. package/dist/__tests__/integration/detect-sdk.test.js +100 -0
  18. package/dist/__tests__/integration/runner.test.js +79 -0
  19. package/dist/cli.js +159 -45
  20. package/dist/codemods/__tests__/__fixtures__/transform-align-experimental-unstable-prefixes.fixtures.js +68 -0
  21. package/dist/codemods/__tests__/__fixtures__/transform-appearance-layout-to-options.fixtures.js +9 -0
  22. package/dist/codemods/__tests__/__fixtures__/transform-clerk-react-v6.fixtures.js +13 -0
  23. package/dist/codemods/__tests__/__fixtures__/transform-remove-deprecated-appearance-props.fixtures.js +63 -0
  24. package/dist/codemods/__tests__/__fixtures__/transform-themes-to-ui-themes.fixtures.js +41 -0
  25. package/dist/codemods/__tests__/transform-align-experimental-unstable-prefixes.test.js +15 -0
  26. package/dist/codemods/__tests__/transform-appearance-layout-to-options.test.js +15 -0
  27. package/dist/codemods/__tests__/transform-remove-deprecated-appearance-props.test.js +15 -0
  28. package/dist/codemods/__tests__/transform-themes-to-ui-themes.test.js +15 -0
  29. package/dist/codemods/index.js +67 -13
  30. package/dist/codemods/transform-align-experimental-unstable-prefixes.cjs +400 -0
  31. package/dist/codemods/transform-appearance-layout-to-options.cjs +65 -0
  32. package/dist/codemods/transform-clerk-react-v6.cjs +15 -7
  33. package/dist/codemods/transform-remove-deprecated-appearance-props.cjs +109 -0
  34. package/dist/codemods/transform-remove-deprecated-props.cjs +12 -12
  35. package/dist/codemods/transform-themes-to-ui-themes.cjs +65 -0
  36. package/dist/config.js +122 -0
  37. package/dist/render.js +164 -0
  38. package/dist/runner.js +98 -0
  39. package/dist/util/detect-sdk.js +125 -0
  40. package/dist/util/package-manager.js +94 -0
  41. package/dist/versions/core-3/changes/clerk-expo-package-rename.md +23 -0
  42. package/dist/versions/core-3/changes/clerk-react-package-rename.md +23 -0
  43. package/dist/versions/core-3/index.js +40 -0
  44. package/package.json +2 -8
  45. package/dist/app.js +0 -177
  46. package/dist/components/Codemod.js +0 -97
  47. package/dist/components/Command.js +0 -56
  48. package/dist/components/Header.js +0 -11
  49. package/dist/components/SDKWorkflow.js +0 -278
  50. package/dist/components/Scan.js +0 -180
  51. package/dist/components/UpgradeSDK.js +0 -116
  52. package/dist/util/expandable-list.js +0 -173
  53. package/dist/util/get-clerk-version.js +0 -22
  54. package/dist/util/guess-framework.js +0 -69
@@ -0,0 +1,400 @@
1
+ const SPECIFIC_RENAMES = {
2
+ experimental_createTheme: 'createTheme',
3
+ __experimental_createTheme: 'createTheme',
4
+ experimental__simple: 'simple',
5
+ __experimental_simple: 'simple',
6
+ __unstable__createClerkClient: 'createClerkClient',
7
+ __unstable_invokeMiddlewareOnAuthStateChange: '__internal_invokeMiddlewareOnAuthStateChange',
8
+ __unstable__environment: '__internal_environment',
9
+ __unstable__updateProps: '__internal_updateProps',
10
+ __unstable__setEnvironment: '__internal_setEnvironment',
11
+ __unstable__onBeforeRequest: '__internal_onBeforeRequest',
12
+ __unstable__onAfterResponse: '__internal_onAfterResponse',
13
+ __unstable__onBeforeSetActive: '__internal_onBeforeSetActive',
14
+ __unstable__onAfterSetActive: '__internal_onAfterSetActive'
15
+ };
16
+ const REMOVED_PROPS = new Set(['__unstable_manageBillingUrl', '__unstable_manageBillingLabel', '__unstable_manageBillingMembersLimit', 'experimental__forceOauthFirst']);
17
+ const UI_THEME_NAMES = new Set(['createTheme', 'simple', 'experimental_createTheme', '__experimental_createTheme', 'experimental__simple', '__experimental_simple']);
18
+ const UI_THEME_SOURCE = '@clerk/ui/themes/experimental';
19
+ const UI_LEGACY_SOURCES = new Set(['@clerk/ui', '@clerk/ui/themes', UI_THEME_SOURCE]);
20
+ const CHROME_CLIENT_NAMES = new Set(['__unstable__createClerkClient', 'createClerkClient']);
21
+ const CHROME_BACKGROUND_SOURCE = '@clerk/chrome-extension/background';
22
+ const CHROME_LEGACY_SOURCE = '@clerk/chrome-extension';
23
+ module.exports = function transformAlignExperimentalUnstablePrefixes({
24
+ source
25
+ }, {
26
+ jscodeshift: j
27
+ }) {
28
+ const root = j(source);
29
+ let dirty = false;
30
+ const maybeRename = name => {
31
+ if (!name || REMOVED_PROPS.has(name)) {
32
+ return null;
33
+ }
34
+ return SPECIFIC_RENAMES[name] ?? null;
35
+ };
36
+ const renameIdentifier = node => {
37
+ const newName = maybeRename(node.name);
38
+ if (newName && newName !== node.name) {
39
+ node.name = newName;
40
+ dirty = true;
41
+ }
42
+ };
43
+ const renameLiteral = node => {
44
+ if (typeof node.value !== 'string') {
45
+ return;
46
+ }
47
+ const newName = maybeRename(node.value);
48
+ if (newName && newName !== node.value) {
49
+ node.value = newName;
50
+ dirty = true;
51
+ }
52
+ };
53
+ const getPropertyName = key => {
54
+ if (j.Identifier.check(key)) {
55
+ return key.name;
56
+ }
57
+ if (j.Literal.check(key)) {
58
+ return key.value;
59
+ }
60
+ if (j.StringLiteral && j.StringLiteral.check(key)) {
61
+ return key.value;
62
+ }
63
+ return null;
64
+ };
65
+ const renamePropertyKey = (key, computed = false) => {
66
+ if (REMOVED_PROPS.has(getPropertyName(key))) {
67
+ return null;
68
+ }
69
+ if (j.Identifier.check(key)) {
70
+ const newName = maybeRename(key.name);
71
+ if (newName && newName !== key.name) {
72
+ key.name = newName;
73
+ dirty = true;
74
+ }
75
+ return key;
76
+ }
77
+ if (!computed && (j.Literal.check(key) || j.StringLiteral && j.StringLiteral.check(key))) {
78
+ const newName = maybeRename(key.value);
79
+ if (newName && newName !== key.value) {
80
+ key.value = newName;
81
+ dirty = true;
82
+ }
83
+ return key;
84
+ }
85
+ return key;
86
+ };
87
+ const mergeImportSpecifiers = (targetImport, specifiers) => {
88
+ const existingKeys = new Set((targetImport.node.specifiers || []).map(spec => `${spec.local ? spec.local.name : spec.imported?.name ?? spec.imported?.value ?? ''}`));
89
+ specifiers.forEach(spec => {
90
+ const key = spec.local ? spec.local.name : spec.imported?.name;
91
+ if (!existingKeys.has(key)) {
92
+ targetImport.node.specifiers = targetImport.node.specifiers || [];
93
+ targetImport.node.specifiers.push(spec);
94
+ existingKeys.add(key);
95
+ dirty = true;
96
+ }
97
+ });
98
+ };
99
+ root.find(j.ImportSpecifier).forEach(path => {
100
+ const imported = path.node.imported;
101
+ if (j.Identifier.check(imported)) {
102
+ const originalImportedName = imported.name;
103
+ renameIdentifier(imported);
104
+ if ((!path.node.local || path.node.local.name === originalImportedName) && imported.name !== originalImportedName) {
105
+ path.node.local = j.identifier(imported.name);
106
+ dirty = true;
107
+ }
108
+ }
109
+ if (path.node.local) {
110
+ renameIdentifier(path.node.local);
111
+ }
112
+ });
113
+ root.find(j.ExportSpecifier).forEach(path => {
114
+ if (j.Identifier.check(path.node.exported)) {
115
+ renameIdentifier(path.node.exported);
116
+ }
117
+ if (j.Identifier.check(path.node.local)) {
118
+ renameIdentifier(path.node.local);
119
+ }
120
+ });
121
+ const handleMemberExpression = path => {
122
+ const {
123
+ node
124
+ } = path;
125
+ if (!node.computed && j.Identifier.check(node.property)) {
126
+ renameIdentifier(node.property);
127
+ } else if (node.computed && (j.Literal.check(node.property) || j.StringLiteral && j.StringLiteral.check(node.property))) {
128
+ renameLiteral(node.property);
129
+ }
130
+ };
131
+ root.find(j.MemberExpression).forEach(handleMemberExpression);
132
+ if (j.OptionalMemberExpression) {
133
+ root.find(j.OptionalMemberExpression).forEach(handleMemberExpression);
134
+ }
135
+ root.find(j.Property).forEach(path => {
136
+ const {
137
+ node
138
+ } = path;
139
+ const propName = getPropertyName(node.key);
140
+ if (propName && REMOVED_PROPS.has(propName) && !node.computed) {
141
+ path.prune();
142
+ dirty = true;
143
+ return;
144
+ }
145
+ renamePropertyKey(node.key, node.computed);
146
+ if (j.Identifier.check(node.value)) {
147
+ renameIdentifier(node.value);
148
+ }
149
+ });
150
+ root.find(j.ObjectPattern).forEach(path => {
151
+ path.node.properties.forEach(prop => {
152
+ if (!prop) {
153
+ return;
154
+ }
155
+ const keyName = getPropertyName(prop.key);
156
+ if (keyName && REMOVED_PROPS.has(keyName) && !prop.computed) {
157
+ return;
158
+ }
159
+ if (prop.key) {
160
+ renamePropertyKey(prop.key, prop.computed);
161
+ }
162
+ if (prop.value && j.Identifier.check(prop.value)) {
163
+ renameIdentifier(prop.value);
164
+ }
165
+ });
166
+ });
167
+ root.find(j.Identifier).forEach(path => {
168
+ renameIdentifier(path.node);
169
+ });
170
+ root.find(j.JSXOpeningElement).forEach(path => {
171
+ const attributes = path.node.attributes || [];
172
+ path.node.attributes = attributes.filter(attr => {
173
+ if (!j.JSXAttribute.check(attr) || !j.JSXIdentifier.check(attr.name)) {
174
+ return true;
175
+ }
176
+ const name = attr.name.name;
177
+ if (REMOVED_PROPS.has(name)) {
178
+ dirty = true;
179
+ return false;
180
+ }
181
+ const newName = maybeRename(name);
182
+ if (newName && newName !== name) {
183
+ attr.name.name = newName;
184
+ dirty = true;
185
+ }
186
+ return true;
187
+ });
188
+ });
189
+ const normalizeUiThemeSpecifier = spec => {
190
+ if (!j.ImportSpecifier.check(spec)) {
191
+ return null;
192
+ }
193
+ const importedName = spec.imported?.name ?? spec.imported?.value;
194
+ if (!importedName || !UI_THEME_NAMES.has(importedName)) {
195
+ return null;
196
+ }
197
+ const newImportedName = maybeRename(importedName) || importedName;
198
+ const newImported = j.identifier(newImportedName);
199
+ const newLocal = spec.local && spec.local.name !== importedName ? j.identifier(spec.local.name) : j.identifier(newImportedName);
200
+ return j.importSpecifier(newImported, newLocal.name === newImported.name ? null : newLocal);
201
+ };
202
+ root.find(j.ImportDeclaration).forEach(path => {
203
+ const source = path.node.source?.value;
204
+ if (!UI_LEGACY_SOURCES.has(source) && source !== CHROME_LEGACY_SOURCE) {
205
+ return;
206
+ }
207
+ if (UI_LEGACY_SOURCES.has(source)) {
208
+ const specifiers = path.node.specifiers || [];
209
+ const moveSpecifiers = [];
210
+ const remainingSpecifiers = [];
211
+ specifiers.forEach(spec => {
212
+ const normalized = normalizeUiThemeSpecifier(spec);
213
+ if (normalized) {
214
+ moveSpecifiers.push(normalized);
215
+ return;
216
+ }
217
+ remainingSpecifiers.push(spec);
218
+ });
219
+ if (source === UI_THEME_SOURCE) {
220
+ if (moveSpecifiers.length) {
221
+ path.node.specifiers = moveSpecifiers.concat(remainingSpecifiers.filter(spec => !moveSpecifiers.some(m => m.imported.name === spec.imported?.name)));
222
+ dirty = true;
223
+ }
224
+ return;
225
+ }
226
+ if (moveSpecifiers.length) {
227
+ const targetImport = root.find(j.ImportDeclaration, {
228
+ source: {
229
+ value: UI_THEME_SOURCE
230
+ }
231
+ }).at(0);
232
+ if (targetImport.size() > 0) {
233
+ mergeImportSpecifiers(targetImport.get(), moveSpecifiers);
234
+ } else {
235
+ const newImport = j.importDeclaration(moveSpecifiers, j.literal(UI_THEME_SOURCE));
236
+ j(path).insertAfter(newImport);
237
+ dirty = true;
238
+ }
239
+ if (remainingSpecifiers.length) {
240
+ path.node.specifiers = remainingSpecifiers;
241
+ } else {
242
+ j(path).remove();
243
+ }
244
+ }
245
+ }
246
+ if (source === CHROME_LEGACY_SOURCE) {
247
+ const specifiers = path.node.specifiers || [];
248
+ const moveSpecifiers = [];
249
+ const remainingSpecifiers = [];
250
+ specifiers.forEach(spec => {
251
+ if (!j.ImportSpecifier.check(spec)) {
252
+ remainingSpecifiers.push(spec);
253
+ return;
254
+ }
255
+ const importedName = spec.imported?.name ?? spec.imported?.value;
256
+ if (!CHROME_CLIENT_NAMES.has(importedName)) {
257
+ remainingSpecifiers.push(spec);
258
+ return;
259
+ }
260
+ const newImportedName = maybeRename(importedName) || importedName;
261
+ const newImported = j.identifier(newImportedName);
262
+ const newLocal = spec.local && spec.local.name !== importedName ? j.identifier(spec.local.name) : j.identifier(newImportedName);
263
+ moveSpecifiers.push(j.importSpecifier(newImported, newLocal.name === newImported.name ? null : newLocal));
264
+ });
265
+ if (moveSpecifiers.length) {
266
+ const targetImport = root.find(j.ImportDeclaration, {
267
+ source: {
268
+ value: CHROME_BACKGROUND_SOURCE
269
+ }
270
+ }).at(0);
271
+ if (targetImport.size() > 0) {
272
+ mergeImportSpecifiers(targetImport.get(), moveSpecifiers);
273
+ } else {
274
+ const newImport = j.importDeclaration(moveSpecifiers, j.literal(CHROME_BACKGROUND_SOURCE));
275
+ j(path).insertAfter(newImport);
276
+ dirty = true;
277
+ }
278
+ if (remainingSpecifiers.length) {
279
+ path.node.specifiers = remainingSpecifiers;
280
+ } else {
281
+ j(path).remove();
282
+ }
283
+ }
284
+ }
285
+ });
286
+ root.find(j.VariableDeclarator, {
287
+ init: {
288
+ callee: {
289
+ name: 'require'
290
+ }
291
+ }
292
+ }).filter(path => {
293
+ const arg = path.node.init.arguments?.[0];
294
+ return arg && (j.Literal.check(arg) || j.StringLiteral && j.StringLiteral.check(arg)) && UI_LEGACY_SOURCES.has(arg.value);
295
+ }).forEach(path => {
296
+ const id = path.node.id;
297
+ if (!j.ObjectPattern.check(id)) {
298
+ return;
299
+ }
300
+ const moveProps = [];
301
+ const keepProps = [];
302
+ id.properties.forEach(prop => {
303
+ if (!prop || !prop.key) {
304
+ return;
305
+ }
306
+ const keyName = getPropertyName(prop.key);
307
+ if (!keyName) {
308
+ keepProps.push(prop);
309
+ return;
310
+ }
311
+ if (!UI_THEME_NAMES.has(keyName)) {
312
+ keepProps.push(prop);
313
+ return;
314
+ }
315
+ const renamed = maybeRename(keyName) || keyName;
316
+ const keyIdentifier = j.identifier(renamed);
317
+ const valueIdentifier = prop.value && j.Identifier.check(prop.value) && prop.value.name !== keyName ? j.identifier(prop.value.name) : j.identifier(renamed);
318
+ const newProp = j.property('init', keyIdentifier, valueIdentifier);
319
+ newProp.shorthand = keyIdentifier.name === valueIdentifier.name;
320
+ moveProps.push(newProp);
321
+ });
322
+ if (!moveProps.length) {
323
+ return;
324
+ }
325
+ const parentDecl = path.parent.node;
326
+ const kind = parentDecl.kind || 'const';
327
+ const newDeclarator = j.variableDeclarator(j.objectPattern(moveProps), j.callExpression(j.identifier('require'), [j.literal(UI_THEME_SOURCE)]));
328
+ const newDeclaration = j.variableDeclaration(kind, [newDeclarator]);
329
+ j(path.parent).insertAfter(newDeclaration);
330
+ dirty = true;
331
+ if (keepProps.length) {
332
+ id.properties = keepProps;
333
+ } else {
334
+ j(path).remove();
335
+ }
336
+ });
337
+ root.find(j.VariableDeclarator, {
338
+ init: {
339
+ callee: {
340
+ name: 'require'
341
+ }
342
+ }
343
+ }).filter(path => {
344
+ const arg = path.node.init.arguments?.[0];
345
+ return arg && (j.Literal.check(arg) || j.StringLiteral && j.StringLiteral.check(arg)) && arg.value === CHROME_LEGACY_SOURCE;
346
+ }).forEach(path => {
347
+ const id = path.node.id;
348
+ if (!j.ObjectPattern.check(id)) {
349
+ return;
350
+ }
351
+ const moveProps = [];
352
+ const keepProps = [];
353
+ id.properties.forEach(prop => {
354
+ if (!prop || !prop.key) {
355
+ return;
356
+ }
357
+ const keyName = getPropertyName(prop.key);
358
+ if (!keyName || !CHROME_CLIENT_NAMES.has(keyName)) {
359
+ keepProps.push(prop);
360
+ return;
361
+ }
362
+ const renamed = maybeRename(keyName) || keyName;
363
+ const keyIdentifier = j.identifier(renamed);
364
+ const valueIdentifier = prop.value && j.Identifier.check(prop.value) && prop.value.name !== keyName ? j.identifier(prop.value.name) : j.identifier(renamed);
365
+ const newProp = j.property('init', keyIdentifier, valueIdentifier);
366
+ newProp.shorthand = keyIdentifier.name === valueIdentifier.name;
367
+ moveProps.push(newProp);
368
+ });
369
+ if (!moveProps.length) {
370
+ return;
371
+ }
372
+ const parentDecl = path.parent.node;
373
+ const kind = parentDecl.kind || 'const';
374
+ const newDeclarator = j.variableDeclarator(j.objectPattern(moveProps), j.callExpression(j.identifier('require'), [j.literal(CHROME_BACKGROUND_SOURCE)]));
375
+ const newDeclaration = j.variableDeclaration(kind, [newDeclarator]);
376
+ j(path.parent).insertAfter(newDeclaration);
377
+ dirty = true;
378
+ if (keepProps.length) {
379
+ id.properties = keepProps;
380
+ } else {
381
+ j(path).remove();
382
+ }
383
+ });
384
+ root.find(j.ObjectExpression).forEach(path => {
385
+ const props = path.node.properties || [];
386
+ path.node.properties = props.filter(prop => {
387
+ if (!prop || !prop.key) {
388
+ return true;
389
+ }
390
+ const propName = getPropertyName(prop.key);
391
+ if (propName && REMOVED_PROPS.has(propName) && !prop.computed) {
392
+ dirty = true;
393
+ return false;
394
+ }
395
+ return true;
396
+ });
397
+ });
398
+ return dirty ? root.toSource() : undefined;
399
+ };
400
+ module.exports.parser = 'tsx';
@@ -0,0 +1,65 @@
1
+ const isStringLiteral = node => node && node.type === 'Literal' && typeof node.value === 'string' || node && node.type === 'StringLiteral' && typeof node.value === 'string';
2
+ const getPropertyName = key => {
3
+ if (!key) {
4
+ return null;
5
+ }
6
+ if (key.type === 'Identifier') {
7
+ return key.name;
8
+ }
9
+ if (isStringLiteral(key)) {
10
+ return key.value;
11
+ }
12
+ return null;
13
+ };
14
+ module.exports = function transformAppearanceLayoutToOptions({
15
+ source
16
+ }, {
17
+ jscodeshift: j
18
+ }) {
19
+ const root = j(source);
20
+ let dirty = false;
21
+ const renameLayoutKey = prop => {
22
+ const keyName = getPropertyName(prop?.key);
23
+ if (!prop || keyName !== 'layout') {
24
+ return false;
25
+ }
26
+ if (prop.computed && !isStringLiteral(prop.key)) {
27
+ return false;
28
+ }
29
+ if (j.Identifier.check(prop.key)) {
30
+ prop.key.name = 'options';
31
+ } else if (isStringLiteral(prop.key)) {
32
+ prop.key.value = 'options';
33
+ } else {
34
+ prop.key = j.identifier('options');
35
+ prop.computed = false;
36
+ }
37
+ return true;
38
+ };
39
+ root.find(j.JSXAttribute, {
40
+ name: {
41
+ name: 'appearance'
42
+ }
43
+ }).forEach(path => {
44
+ const {
45
+ value
46
+ } = path.node;
47
+ if (!value || !j.JSXExpressionContainer.check(value)) {
48
+ return;
49
+ }
50
+ const expression = value.expression;
51
+ if (j.ObjectExpression.check(expression)) {
52
+ let changed = false;
53
+ (expression.properties || []).forEach(prop => {
54
+ if (renameLayoutKey(prop)) {
55
+ changed = true;
56
+ }
57
+ });
58
+ if (changed) {
59
+ dirty = true;
60
+ }
61
+ }
62
+ });
63
+ return dirty ? root.toSource() : undefined;
64
+ };
65
+ module.exports.parser = 'tsx';
@@ -42,16 +42,18 @@ module.exports = function transformClerkReactV6({
42
42
  }
43
43
  if (legacySpecifiers.length > 0 && nonLegacySpecifiers.length > 0) {
44
44
  // Mixed import: keep non-legacy on targetPackage, emit a new import for legacy hooks
45
- node.specifiers = nonLegacySpecifiers;
46
- node.source = j.literal(targetPackage);
45
+ // Use replaceWith to avoid formatting issues with insertAfter
46
+ const mainImport = j.importDeclaration(nonLegacySpecifiers, j.stringLiteral(targetPackage));
47
47
  if (importKind) {
48
- node.importKind = importKind;
48
+ mainImport.importKind = importKind;
49
49
  }
50
- const legacyImportDecl = j.importDeclaration(legacySpecifiers, j.literal(`${targetPackage}/legacy`));
50
+ // Preserve leading comments/whitespace from original import
51
+ mainImport.comments = node.comments;
52
+ const legacyImport = j.importDeclaration(legacySpecifiers, j.stringLiteral(`${targetPackage}/legacy`));
51
53
  if (importKind) {
52
- legacyImportDecl.importKind = importKind;
54
+ legacyImport.importKind = importKind;
53
55
  }
54
- j(path).insertAfter(legacyImportDecl);
56
+ j(path).replaceWith([mainImport, legacyImport]);
55
57
  dirtyFlag = true;
56
58
  return;
57
59
  }
@@ -127,6 +129,12 @@ module.exports = function transformClerkReactV6({
127
129
  dirtyFlag = true;
128
130
  });
129
131
  });
130
- return dirtyFlag ? root.toSource() : undefined;
132
+ if (!dirtyFlag) {
133
+ return undefined;
134
+ }
135
+ let result = root.toSource();
136
+ // Fix double semicolons that can occur when recast reprints directive prologues (e.g., "use client";)
137
+ result = result.replace(/^(['"`][^'"`]+['"`]);;/gm, '$1;');
138
+ return result;
131
139
  };
132
140
  module.exports.parser = 'tsx';
@@ -0,0 +1,109 @@
1
+ const VARIABLE_RENAMES = {
2
+ colorText: 'colorForeground',
3
+ colorTextSecondary: 'colorMutedForeground',
4
+ colorInputText: 'colorInputForeground',
5
+ colorInputBackground: 'colorInput',
6
+ colorTextOnPrimaryBackground: 'colorPrimaryForeground',
7
+ spacingUnit: 'spacing'
8
+ };
9
+ const isStringLiteral = node => node && node.type === 'Literal' && typeof node.value === 'string' || node && node.type === 'StringLiteral' && typeof node.value === 'string';
10
+ const getKeyName = key => {
11
+ if (!key) {
12
+ return null;
13
+ }
14
+ if (key.type === 'Identifier') {
15
+ return key.name;
16
+ }
17
+ if (isStringLiteral(key)) {
18
+ return key.value;
19
+ }
20
+ return null;
21
+ };
22
+ module.exports = function transformRemoveDeprecatedAppearanceProps({
23
+ source
24
+ }, {
25
+ jscodeshift: j
26
+ }) {
27
+ const root = j(source);
28
+ let dirty = false;
29
+ const renamePropertyKey = (prop, newName) => {
30
+ if (j.Identifier.check(prop.key)) {
31
+ prop.key.name = newName;
32
+ } else if (isStringLiteral(prop.key)) {
33
+ prop.key.value = newName;
34
+ } else {
35
+ prop.key = j.identifier(newName);
36
+ prop.computed = false;
37
+ }
38
+ dirty = true;
39
+ };
40
+ const maybeRenameBaseTheme = prop => {
41
+ if (!prop || prop.computed) {
42
+ return;
43
+ }
44
+ if (getKeyName(prop.key) === 'baseTheme') {
45
+ renamePropertyKey(prop, 'theme');
46
+ }
47
+ };
48
+ const maybeRenameVariableKey = prop => {
49
+ if (!prop || prop.computed) {
50
+ return;
51
+ }
52
+ const keyName = getKeyName(prop.key);
53
+ const newName = VARIABLE_RENAMES[keyName];
54
+ if (newName) {
55
+ renamePropertyKey(prop, newName);
56
+ }
57
+ };
58
+ const transformAppearanceObject = objExpr => {
59
+ const props = objExpr.properties || [];
60
+ props.forEach(prop => {
61
+ if (!prop || !prop.key) {
62
+ return;
63
+ }
64
+ maybeRenameBaseTheme(prop);
65
+ if (getKeyName(prop.key) === 'variables' && j.ObjectExpression.check(prop.value)) {
66
+ (prop.value.properties || []).forEach(maybeRenameVariableKey);
67
+ }
68
+ });
69
+ };
70
+ const findObjectForIdentifier = identifier => {
71
+ if (!identifier || !j.Identifier.check(identifier)) {
72
+ return null;
73
+ }
74
+ const name = identifier.name;
75
+ const decl = root.find(j.VariableDeclarator, {
76
+ id: {
77
+ type: 'Identifier',
78
+ name
79
+ }
80
+ }).filter(p => j.ObjectExpression.check(p.node.init)).at(0);
81
+ if (decl.size() === 0) {
82
+ return null;
83
+ }
84
+ return decl.get().node.init;
85
+ };
86
+ root.find(j.JSXAttribute, {
87
+ name: {
88
+ name: 'appearance'
89
+ }
90
+ }).forEach(path => {
91
+ const {
92
+ value
93
+ } = path.node;
94
+ if (!value || !j.JSXExpressionContainer.check(value)) {
95
+ return;
96
+ }
97
+ const expr = value.expression;
98
+ if (j.ObjectExpression.check(expr)) {
99
+ transformAppearanceObject(expr);
100
+ } else if (j.Identifier.check(expr)) {
101
+ const obj = findObjectForIdentifier(expr);
102
+ if (obj) {
103
+ transformAppearanceObject(obj);
104
+ }
105
+ }
106
+ });
107
+ return dirty ? root.toSource() : undefined;
108
+ };
109
+ module.exports.parser = 'tsx';
@@ -22,8 +22,9 @@ const ORGANIZATION_SWITCHER_RENAMES = new Map([['afterSwitchOrganizationUrl', 'a
22
22
  module.exports = function transformDeprecatedProps({
23
23
  source
24
24
  }, {
25
- jscodeshift: j
26
- }, options = {}) {
25
+ jscodeshift: j,
26
+ stats
27
+ }) {
27
28
  const root = j(source);
28
29
  let dirty = false;
29
30
  const {
@@ -39,19 +40,17 @@ module.exports = function transformDeprecatedProps({
39
40
  if (COMPONENTS_WITH_HIDE_SLUG.has(canonicalName)) {
40
41
  if (removeJsxAttribute(j, jsxNode, 'hideSlug')) {
41
42
  dirty = true;
43
+ stats('hideSlugRemoved');
42
44
  }
43
45
  }
44
46
  if (COMPONENTS_WITH_USER_BUTTON_REMOVALS.has(canonicalName)) {
45
- let removedCount = 0;
46
- for (const attrName of COMPONENTS_WITH_USER_BUTTON_REMOVALS.get(canonicalName)) {
47
+ const propsToRemove = COMPONENTS_WITH_USER_BUTTON_REMOVALS.get(canonicalName);
48
+ for (const attrName of propsToRemove) {
47
49
  if (removeJsxAttribute(j, jsxNode, attrName)) {
48
50
  dirty = true;
49
- removedCount += 1;
51
+ stats('userbuttonAfterSignOutPropsRemoved');
50
52
  }
51
53
  }
52
- if (removedCount > 0 && options.clerkUpgradeStats) {
53
- options.clerkUpgradeStats.userbuttonAfterSignOutPropsRemoved = (options.clerkUpgradeStats.userbuttonAfterSignOutPropsRemoved || 0) + removedCount;
54
- }
55
54
  }
56
55
  if (COMPONENT_RENAMES.has(canonicalName)) {
57
56
  const renameMap = COMPONENT_RENAMES.get(canonicalName);
@@ -101,7 +100,7 @@ module.exports = function transformDeprecatedProps({
101
100
  if (renameObjectProperties(root, j, 'activeSessions', 'signedInSessions')) {
102
101
  dirty = true;
103
102
  }
104
- if (transformSetActiveBeforeEmit(root, j)) {
103
+ if (transformSetActiveBeforeEmit(root, j, stats)) {
105
104
  dirty = true;
106
105
  }
107
106
  if (renameTypeReferences(root, j, 'ClerkMiddlewareAuthObject', 'ClerkMiddlewareSessionAuthObject')) {
@@ -324,7 +323,7 @@ function renameTSPropertySignatures(root, j, oldName, newName) {
324
323
  });
325
324
  return changed;
326
325
  }
327
- function transformSetActiveBeforeEmit(root, j) {
326
+ function transformSetActiveBeforeEmit(root, j, stats) {
328
327
  let changed = false;
329
328
  root.find(j.CallExpression).filter(path => isSetActiveCall(path.node.callee)).forEach(path => {
330
329
  const [args0] = path.node.arguments;
@@ -348,6 +347,7 @@ function transformSetActiveBeforeEmit(root, j) {
348
347
  const navigateProp = j.objectProperty(j.identifier('navigate'), buildNavigateArrowFunction(j, originalValue));
349
348
  args0.properties.splice(beforeEmitIndex, 1, navigateProp);
350
349
  changed = true;
350
+ stats('beforeEmitTransformed');
351
351
  });
352
352
  return changed;
353
353
  }
@@ -378,8 +378,8 @@ function getPropertyValueExpression(valueNode) {
378
378
  }
379
379
  function buildNavigateArrowFunction(j, originalExpression) {
380
380
  const paramIdentifier = j.identifier('params');
381
- const calleeExpression = clone(originalExpression);
382
- const callExpression = j.callExpression(calleeExpression, [j.memberExpression(paramIdentifier, j.identifier('session'))]);
381
+ // No need to clone - we're moving the expression from beforeEmit to navigate
382
+ const callExpression = j.callExpression(originalExpression, [j.memberExpression(paramIdentifier, j.identifier('session'))]);
383
383
  return j.arrowFunctionExpression([paramIdentifier], callExpression);
384
384
  }
385
385
  function renameTypeReferences(root, j, oldName, newName) {