@clerk/upgrade 2.0.0-snapshot.v20251203203405 → 2.0.0-snapshot.v20251204175016

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.
@@ -3,7 +3,7 @@ import { fileURLToPath } from 'node:url';
3
3
  import { globby } from 'globby';
4
4
  import { run } from 'jscodeshift/src/Runner.js';
5
5
  const __dirname = dirname(fileURLToPath(import.meta.url));
6
- export async function runCodemod(transform = 'transform-async-request', glob, options) {
6
+ export async function runCodemod(transform = 'transform-async-request', glob, options = {}) {
7
7
  if (!transform) {
8
8
  throw new Error('No transform provided');
9
9
  }
@@ -16,10 +16,17 @@ export async function runCodemod(transform = 'transform-async-request', glob, op
16
16
  '**/*.(css|scss|sass|less|styl)+' // common style files
17
17
  ]
18
18
  });
19
- return await run(resolvedPath, paths ?? [], {
19
+ const clerkUpgradeStats = options.clerkUpgradeStats ?? {};
20
+ const result = await run(resolvedPath, paths ?? [], {
20
21
  dry: false,
21
22
  ...options,
23
+ // expose a mutable stats bag so individual transforms can record structured information
24
+ clerkUpgradeStats,
22
25
  // we must silence stdout to prevent output from interfering with ink CLI
23
26
  silent: true
24
27
  });
28
+ return {
29
+ ...result,
30
+ clerkUpgradeStats
31
+ };
25
32
  }
@@ -20,12 +20,14 @@ const COMPONENT_REDIRECT_ATTR = new Map([['ClerkProvider', {
20
20
  const COMPONENTS_WITH_USER_BUTTON_REMOVALS = new Map([['UserButton', ['afterSignOutUrl', 'afterMultiSessionSingleSignOutUrl']]]);
21
21
  const ORGANIZATION_SWITCHER_RENAMES = new Map([['afterSwitchOrganizationUrl', 'afterSelectOrganizationUrl']]);
22
22
  module.exports = function transformDeprecatedProps({
23
- source
23
+ source,
24
+ path: filePath
24
25
  }, {
25
26
  jscodeshift: j
26
- }) {
27
+ }, options = {}) {
27
28
  const root = j(source);
28
29
  let dirty = false;
30
+ const stats = options.clerkUpgradeStats;
29
31
  const {
30
32
  namedImports,
31
33
  namespaceImports
@@ -39,12 +41,29 @@ module.exports = function transformDeprecatedProps({
39
41
  if (COMPONENTS_WITH_HIDE_SLUG.has(canonicalName)) {
40
42
  if (removeJsxAttribute(j, jsxNode, 'hideSlug')) {
41
43
  dirty = true;
44
+ if (stats) {
45
+ stats.hideSlugRemoved = (stats.hideSlugRemoved || 0) + 1;
46
+ stats.hideSlugFiles = stats.hideSlugFiles || [];
47
+ if (!stats.hideSlugFiles.includes(filePath)) {
48
+ stats.hideSlugFiles.push(filePath);
49
+ }
50
+ }
42
51
  }
43
52
  }
44
53
  if (COMPONENTS_WITH_USER_BUTTON_REMOVALS.has(canonicalName)) {
45
- for (const attrName of COMPONENTS_WITH_USER_BUTTON_REMOVALS.get(canonicalName)) {
54
+ const propsToRemove = COMPONENTS_WITH_USER_BUTTON_REMOVALS.get(canonicalName);
55
+ let removedCount = 0;
56
+ for (const attrName of propsToRemove) {
46
57
  if (removeJsxAttribute(j, jsxNode, attrName)) {
47
58
  dirty = true;
59
+ removedCount += 1;
60
+ }
61
+ }
62
+ if (removedCount > 0 && stats) {
63
+ stats.userbuttonAfterSignOutPropsRemoved = (stats.userbuttonAfterSignOutPropsRemoved || 0) + removedCount;
64
+ stats.userbuttonFilesAffected = stats.userbuttonFilesAffected || [];
65
+ if (!stats.userbuttonFilesAffected.includes(filePath)) {
66
+ stats.userbuttonFilesAffected.push(filePath);
48
67
  }
49
68
  }
50
69
  }
@@ -96,7 +115,7 @@ module.exports = function transformDeprecatedProps({
96
115
  if (renameObjectProperties(root, j, 'activeSessions', 'signedInSessions')) {
97
116
  dirty = true;
98
117
  }
99
- if (transformSetActiveBeforeEmit(root, j)) {
118
+ if (transformSetActiveBeforeEmit(root, j, stats, filePath)) {
100
119
  dirty = true;
101
120
  }
102
121
  if (renameTypeReferences(root, j, 'ClerkMiddlewareAuthObject', 'ClerkMiddlewareSessionAuthObject')) {
@@ -319,7 +338,7 @@ function renameTSPropertySignatures(root, j, oldName, newName) {
319
338
  });
320
339
  return changed;
321
340
  }
322
- function transformSetActiveBeforeEmit(root, j) {
341
+ function transformSetActiveBeforeEmit(root, j, stats, filePath) {
323
342
  let changed = false;
324
343
  root.find(j.CallExpression).filter(path => isSetActiveCall(path.node.callee)).forEach(path => {
325
344
  const [args0] = path.node.arguments;
@@ -343,6 +362,13 @@ function transformSetActiveBeforeEmit(root, j) {
343
362
  const navigateProp = j.objectProperty(j.identifier('navigate'), buildNavigateArrowFunction(j, originalValue));
344
363
  args0.properties.splice(beforeEmitIndex, 1, navigateProp);
345
364
  changed = true;
365
+ if (stats) {
366
+ stats.beforeEmitTransformed = (stats.beforeEmitTransformed || 0) + 1;
367
+ stats.beforeEmitFiles = stats.beforeEmitFiles || [];
368
+ if (!stats.beforeEmitFiles.includes(filePath)) {
369
+ stats.beforeEmitFiles.push(filePath);
370
+ }
371
+ }
346
372
  });
347
373
  return changed;
348
374
  }
@@ -77,7 +77,73 @@ export function Codemod(props) {
77
77
  color: "yellow"
78
78
  }, result.skip ?? 0, " skipped"), /*#__PURE__*/React.createElement(Text, {
79
79
  color: "gray"
80
- }, result.nochange ?? 0, " unmodified"), result.timeElapsed && /*#__PURE__*/React.createElement(Text, null, "Time elapsed: ", result.timeElapsed), /*#__PURE__*/React.createElement(Newline, null)), error && /*#__PURE__*/React.createElement(Text, {
80
+ }, result.nochange ?? 0, " unmodified"), result.timeElapsed && /*#__PURE__*/React.createElement(Text, null, "Time elapsed: ", result.timeElapsed), transform === 'transform-remove-deprecated-props' && /*#__PURE__*/React.createElement(ManualInterventionSummary, {
81
+ stats: result.clerkUpgradeStats
82
+ }), /*#__PURE__*/React.createElement(Newline, null)), error && /*#__PURE__*/React.createElement(Text, {
81
83
  color: "red"
82
84
  }, error.message));
85
+ }
86
+ function ManualInterventionSummary({
87
+ stats
88
+ }) {
89
+ if (!stats) {
90
+ return null;
91
+ }
92
+ const hasUserButtonChanges = stats.userbuttonAfterSignOutPropsRemoved > 0;
93
+ const hasHideSlugChanges = stats.hideSlugRemoved > 0;
94
+ const hasBeforeEmitChanges = stats.beforeEmitTransformed > 0;
95
+ if (!hasUserButtonChanges && !hasHideSlugChanges && !hasBeforeEmitChanges) {
96
+ return null;
97
+ }
98
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Newline, null), /*#__PURE__*/React.createElement(Text, {
99
+ bold: true,
100
+ color: "yellow"
101
+ }, "\u26A0\uFE0F Manual intervention may be required:"), hasUserButtonChanges && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Newline, null), /*#__PURE__*/React.createElement(Text, {
102
+ color: "yellow"
103
+ }, "\u2022 Removed ", stats.userbuttonAfterSignOutPropsRemoved, " ", /*#__PURE__*/React.createElement(Text, {
104
+ bold: true
105
+ }, "UserButton"), " sign-out redirect prop(s)"), /*#__PURE__*/React.createElement(Text, {
106
+ color: "gray"
107
+ }, ' ', "Configure redirects via ", /*#__PURE__*/React.createElement(Text, {
108
+ italic: true
109
+ }, "ClerkProvider afterSignOutUrl"), " or", ' ', /*#__PURE__*/React.createElement(Text, {
110
+ italic: true
111
+ }, "SignOutButton redirectUrl")), /*#__PURE__*/React.createElement(FileList, {
112
+ files: stats.userbuttonFilesAffected
113
+ })), hasHideSlugChanges && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Newline, null), /*#__PURE__*/React.createElement(Text, {
114
+ color: "yellow"
115
+ }, "\u2022 Removed ", stats.hideSlugRemoved, " ", /*#__PURE__*/React.createElement(Text, {
116
+ bold: true
117
+ }, "hideSlug"), " prop(s)"), /*#__PURE__*/React.createElement(Text, {
118
+ color: "gray"
119
+ }, ' ', "This prop has been removed. Slug visibility is now controlled differently."), /*#__PURE__*/React.createElement(FileList, {
120
+ files: stats.hideSlugFiles
121
+ })), hasBeforeEmitChanges && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Newline, null), /*#__PURE__*/React.createElement(Text, {
122
+ color: "yellow"
123
+ }, "\u2022 Transformed ", stats.beforeEmitTransformed, " ", /*#__PURE__*/React.createElement(Text, {
124
+ bold: true
125
+ }, "setActive beforeEmit"), " to", ' ', /*#__PURE__*/React.createElement(Text, {
126
+ bold: true
127
+ }, "navigate")), /*#__PURE__*/React.createElement(Text, {
128
+ color: "gray"
129
+ }, ' ', "Callback signature changed: now receives ", /*#__PURE__*/React.createElement(Text, {
130
+ italic: true
131
+ }, "params"), " object instead of", ' ', /*#__PURE__*/React.createElement(Text, {
132
+ italic: true
133
+ }, "session"), " directly. Review the transformed code."), /*#__PURE__*/React.createElement(FileList, {
134
+ files: stats.beforeEmitFiles
135
+ })));
136
+ }
137
+ function FileList({
138
+ files
139
+ }) {
140
+ if (!files?.length) {
141
+ return null;
142
+ }
143
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Text, {
144
+ color: "gray"
145
+ }, ' ', "Files:"), files.map((file, index) => /*#__PURE__*/React.createElement(Text, {
146
+ key: index,
147
+ color: "gray"
148
+ }, ' ', "- ", file)));
83
149
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clerk/upgrade",
3
- "version": "2.0.0-snapshot.v20251203203405",
3
+ "version": "2.0.0-snapshot.v20251204175016",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/clerk/javascript.git",