@clerk/upgrade 1.1.0-snapshot.vfbd7c17 → 1.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.
- package/dist/app.js +27 -15
- package/dist/cli.js +3 -4
- package/dist/codemods/__tests__/__fixtures__/transform-async-request.fixtures.js +24 -0
- package/dist/codemods/__tests__/__fixtures__/transform-clerk-provider-dynamic.fixtures.js +45 -0
- package/dist/codemods/__tests__/transform-clerk-provider-dynamic.test.js +15 -0
- package/dist/codemods/index.js +4 -1
- package/dist/codemods/transform-async-request.cjs +1 -7
- package/dist/codemods/transform-clerk-provider-dynamic.cjs +50 -0
- package/dist/components/Codemod.js +14 -10
- package/dist/components/Command.js +56 -0
- package/dist/components/SDKWorkflow.js +52 -29
- package/dist/components/Scan.js +15 -17
- package/dist/components/UpgradeSDK.js +70 -0
- package/package.json +1 -1
- package/dist/util/detect-package-manager.js +0 -22
package/dist/app.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { MultiSelect, Select, TextInput } from '@inkjs/ui';
|
|
2
|
-
import { Newline, Text } from 'ink';
|
|
3
|
-
import React, { useState } from 'react';
|
|
2
|
+
import { Newline, Text, useApp } from 'ink';
|
|
3
|
+
import React, { useEffect, useState } from 'react';
|
|
4
4
|
import { Header } from './components/Header.js';
|
|
5
5
|
import { Scan } from './components/Scan.js';
|
|
6
6
|
import { SDKWorkflow } from './components/SDKWorkflow.js';
|
|
@@ -28,20 +28,19 @@ export default function App(props) {
|
|
|
28
28
|
noWarnings = false,
|
|
29
29
|
disableTelemetry = false
|
|
30
30
|
} = props;
|
|
31
|
+
const {
|
|
32
|
+
exit
|
|
33
|
+
} = useApp();
|
|
31
34
|
const [yolo, setYolo] = useState(props.yolo ?? false);
|
|
32
35
|
const [sdks, setSdks] = useState(props.sdk ? [props.sdk] : []);
|
|
33
36
|
const [sdkGuesses, setSdkGuesses] = useState([]);
|
|
34
37
|
const [sdkGuessConfirmed, setSdkGuessConfirmed] = useState(false);
|
|
35
38
|
const [sdkGuessAttempted, setSdkGuessAttempted] = useState(false);
|
|
36
|
-
// See comments below, can be enabled on next major
|
|
37
|
-
|
|
38
|
-
// eslint-disable-next-line no-unused-vars
|
|
39
39
|
const [fromVersion, setFromVersion] = useState(props.fromVersion);
|
|
40
40
|
const [fromVersionGuessAttempted, setFromVersionGuessAttempted] = useState(false);
|
|
41
|
-
// eslint-disable-next-line no-unused-vars
|
|
42
41
|
const [toVersion, setToVersion] = useState(props.toVersion);
|
|
43
42
|
const [dir, setDir] = useState(props.dir);
|
|
44
|
-
const [ignore, setIgnore] = useState(props.ignore);
|
|
43
|
+
const [ignore, setIgnore] = useState(props.ignore ?? []);
|
|
45
44
|
const [configComplete, setConfigComplete] = useState(false);
|
|
46
45
|
const [configVerified, setConfigVerified] = useState(false);
|
|
47
46
|
const [uuid, setUuid] = useState();
|
|
@@ -50,9 +49,19 @@ export default function App(props) {
|
|
|
50
49
|
setSdks(SDKS.map(s => s.value));
|
|
51
50
|
setYolo(false);
|
|
52
51
|
}
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
if (toVersion === 'core-2') {
|
|
54
|
+
setFromVersion('core-1');
|
|
55
|
+
}
|
|
56
|
+
}, [toVersion]);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (fromVersion === 'core-1') {
|
|
59
|
+
setToVersion('core-2');
|
|
60
|
+
}
|
|
61
|
+
}, [fromVersion]);
|
|
53
62
|
|
|
54
63
|
// Handle the individual SDK upgrade
|
|
55
|
-
if (sdks
|
|
64
|
+
if (!fromVersion && !toVersion && sdks[0] === 'nextjs') {
|
|
56
65
|
return /*#__PURE__*/React.createElement(SDKWorkflow, {
|
|
57
66
|
packageManager: props.packageManager,
|
|
58
67
|
sdk: sdks[0]
|
|
@@ -68,7 +77,6 @@ export default function App(props) {
|
|
|
68
77
|
guesses,
|
|
69
78
|
_uuid
|
|
70
79
|
} = guessFrameworks(dir, disableTelemetry);
|
|
71
|
-
// console.log({ guesses, _uuid });
|
|
72
80
|
setUuid(_uuid);
|
|
73
81
|
setSdkGuesses(guesses);
|
|
74
82
|
setSdkGuessAttempted(true);
|
|
@@ -97,7 +105,9 @@ export default function App(props) {
|
|
|
97
105
|
color: "blue"
|
|
98
106
|
}, "Hello friend!"), " We're excited to help you upgrade Clerk modules. Before we get started, a couple questions..."), /*#__PURE__*/React.createElement(Newline, null)), isEmpty(sdks) && !isEmpty(sdkGuesses) && !sdkGuessConfirmed && /*#__PURE__*/React.createElement(React.Fragment, null, sdkGuesses.length > 1 ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Text, null, "It looks like you are using the following Clerk SDKs in your project:"), sdkGuesses.map(guess => /*#__PURE__*/React.createElement(Text, {
|
|
99
107
|
key: guess.value
|
|
100
|
-
}, ' ', "- ", guess.label)), /*#__PURE__*/React.createElement(Text, null, "Is that right?")) : /*#__PURE__*/React.createElement(Text, null, "It looks like you are using the
|
|
108
|
+
}, ' ', "- ", guess.label)), /*#__PURE__*/React.createElement(Text, null, "Is that right?")) : /*#__PURE__*/React.createElement(Text, null, "It looks like you are using the ", /*#__PURE__*/React.createElement(Text, {
|
|
109
|
+
bold: true
|
|
110
|
+
}, sdkGuesses[0].label), " Clerk SDK in your project. Is that right?"), /*#__PURE__*/React.createElement(Select, {
|
|
101
111
|
options: [{
|
|
102
112
|
label: 'yes',
|
|
103
113
|
value: 'yes'
|
|
@@ -110,6 +120,8 @@ export default function App(props) {
|
|
|
110
120
|
// if true, we were right so we set the sdk
|
|
111
121
|
if (item === 'yes') {
|
|
112
122
|
setSdks(sdkGuesses.map(guess => guess.value));
|
|
123
|
+
} else {
|
|
124
|
+
setSdkGuesses([]);
|
|
113
125
|
}
|
|
114
126
|
}
|
|
115
127
|
})), isEmpty(sdks) && isEmpty(sdkGuesses) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Text, null, "Please select which Clerk SDK(s) you're using for your app:"), /*#__PURE__*/React.createElement(Text, {
|
|
@@ -145,14 +157,14 @@ export default function App(props) {
|
|
|
145
157
|
}, " ", ignore.join(', ')))), /*#__PURE__*/React.createElement(Newline, null), /*#__PURE__*/React.createElement(Text, null, "Does this look right?"), /*#__PURE__*/React.createElement(Select, {
|
|
146
158
|
options: [{
|
|
147
159
|
label: 'yes',
|
|
148
|
-
value:
|
|
160
|
+
value: 'yes'
|
|
149
161
|
}, {
|
|
150
|
-
label: 'no - exit, and
|
|
151
|
-
value:
|
|
162
|
+
label: 'no - exit, and I will try again',
|
|
163
|
+
value: 'no'
|
|
152
164
|
}],
|
|
153
165
|
onChange: value => {
|
|
154
|
-
if (!value) {
|
|
155
|
-
|
|
166
|
+
if (!value || value === 'no') {
|
|
167
|
+
exit();
|
|
156
168
|
} else {
|
|
157
169
|
setConfigVerified(true);
|
|
158
170
|
}
|
package/dist/cli.js
CHANGED
|
@@ -21,16 +21,15 @@ const cli = meow(`
|
|
|
21
21
|
Examples
|
|
22
22
|
$ clerk-upgrade --sdk=nextjs --dir=src/**
|
|
23
23
|
$ clerk-upgrade --ignore=**/public/** --ignore=**/dist/**
|
|
24
|
+
$ clerk-upgrade --from=core-1 --to=core-2
|
|
24
25
|
`, {
|
|
25
26
|
importMeta: import.meta,
|
|
26
27
|
flags: {
|
|
27
28
|
from: {
|
|
28
|
-
type: 'string'
|
|
29
|
-
default: 'core-1'
|
|
29
|
+
type: 'string'
|
|
30
30
|
},
|
|
31
31
|
to: {
|
|
32
|
-
type: 'string'
|
|
33
|
-
default: 'core-2'
|
|
32
|
+
type: 'string'
|
|
34
33
|
},
|
|
35
34
|
sdk: {
|
|
36
35
|
type: 'string',
|
|
@@ -178,6 +178,30 @@ export default clerkMiddleware(
|
|
|
178
178
|
},
|
|
179
179
|
);
|
|
180
180
|
`
|
|
181
|
+
}, {
|
|
182
|
+
name: 'Complex clerkMiddleware() without protect()',
|
|
183
|
+
source: `
|
|
184
|
+
import { clerkMiddleware } from '@clerk/nextjs/server';
|
|
185
|
+
|
|
186
|
+
export default clerkMiddleware(
|
|
187
|
+
(auth, req) => {
|
|
188
|
+
const { redirectToSignIn } = auth();
|
|
189
|
+
|
|
190
|
+
redirectToSignIn();
|
|
191
|
+
},
|
|
192
|
+
);
|
|
193
|
+
`,
|
|
194
|
+
output: `
|
|
195
|
+
import { clerkMiddleware } from '@clerk/nextjs/server';
|
|
196
|
+
|
|
197
|
+
export default clerkMiddleware(
|
|
198
|
+
async (auth, req) => {
|
|
199
|
+
const { redirectToSignIn } = await auth();
|
|
200
|
+
|
|
201
|
+
redirectToSignIn();
|
|
202
|
+
},
|
|
203
|
+
);
|
|
204
|
+
`
|
|
181
205
|
}, {
|
|
182
206
|
name: 'Does not transform other imports',
|
|
183
207
|
source: `
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export const fixtures = [{
|
|
2
|
+
name: 'Basic await transform',
|
|
3
|
+
source: `
|
|
4
|
+
import { ClerkProvider } from '@clerk/nextjs'
|
|
5
|
+
|
|
6
|
+
export default function RootLayout({ children }) {
|
|
7
|
+
return (
|
|
8
|
+
<ClerkProvider>
|
|
9
|
+
<html>
|
|
10
|
+
<body>{children}</body>
|
|
11
|
+
</html>
|
|
12
|
+
</ClerkProvider>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
`,
|
|
16
|
+
output: `
|
|
17
|
+
import { ClerkProvider } from '@clerk/nextjs'
|
|
18
|
+
|
|
19
|
+
export default function RootLayout({ children }) {
|
|
20
|
+
return (
|
|
21
|
+
(<ClerkProvider dynamic>
|
|
22
|
+
<html>
|
|
23
|
+
<body>{children}</body>
|
|
24
|
+
</html>
|
|
25
|
+
</ClerkProvider>)
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
`
|
|
29
|
+
}, {
|
|
30
|
+
name: 'Does not transform if ClerkProvider is already dynamic',
|
|
31
|
+
source: `
|
|
32
|
+
import { ClerkProvider } from '@clerk/nextjs'
|
|
33
|
+
|
|
34
|
+
export default function RootLayout({ children }) {
|
|
35
|
+
return (
|
|
36
|
+
<ClerkProvider dynamic>
|
|
37
|
+
<html>
|
|
38
|
+
<body>{children}</body>
|
|
39
|
+
</html>
|
|
40
|
+
</ClerkProvider>
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
`,
|
|
44
|
+
output: ''
|
|
45
|
+
}];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { applyTransform } from 'jscodeshift/dist/testUtils';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import transformer from '../transform-clerk-provider-dynamic.cjs';
|
|
4
|
+
import { fixtures } from './__fixtures__/transform-clerk-provider-dynamic.fixtures';
|
|
5
|
+
describe('transform-clerk-provider-dynamic', () => {
|
|
6
|
+
it.each(fixtures)(`$name`, ({
|
|
7
|
+
source,
|
|
8
|
+
output
|
|
9
|
+
}) => {
|
|
10
|
+
const result = applyTransform(transformer, {}, {
|
|
11
|
+
source
|
|
12
|
+
});
|
|
13
|
+
expect(result).toEqual(output.trim());
|
|
14
|
+
});
|
|
15
|
+
});
|
package/dist/codemods/index.js
CHANGED
|
@@ -3,7 +3,10 @@ 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
|
|
6
|
+
export async function runCodemod(transform, glob, options) {
|
|
7
|
+
if (!transform) {
|
|
8
|
+
throw new Error('No transform provided');
|
|
9
|
+
}
|
|
7
10
|
const resolvedPath = resolve(__dirname, `${transform}.cjs`);
|
|
8
11
|
const paths = await globby(glob, {
|
|
9
12
|
ignore: ['**/*.md', 'node_modules/**', '**/node_modules/**', '.git/**', '**/*.json', 'package.json', '**/package.json', 'package-lock.json', '**/package-lock.json', 'yarn.lock', '**/yarn.lock', 'pnpm-lock.yaml', '**/pnpm-lock.yaml', 'yalc.lock', '**/*.(ico|png|webp|svg|gif|jpg|jpeg)+',
|
|
@@ -116,12 +116,6 @@ module.exports = function transformAsyncRequest({
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
});
|
|
119
|
-
|
|
120
|
-
if (process.env.NODE_ENV !== 'test') {
|
|
121
|
-
console.log(`changed: ${path}`);
|
|
122
|
-
}
|
|
123
|
-
return root.toSource();
|
|
124
|
-
}
|
|
125
|
-
return undefined;
|
|
119
|
+
return dirtyFlag ? root.toSource() : undefined;
|
|
126
120
|
};
|
|
127
121
|
module.exports.parser = 'tsx';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transforms the source code by adding the dynamic prop to the ClerkProvider
|
|
3
|
+
*
|
|
4
|
+
* @param {import('jscodeshift').FileInfo} FileInfo - The parameters object
|
|
5
|
+
* @param {import('jscodeshift').API} api - The API object provided by jscodeshift
|
|
6
|
+
* @param {Object} _options - Additional options (unused)
|
|
7
|
+
* @returns {string|undefined} - The transformed source code if modifications were made, otherwise undefined
|
|
8
|
+
*/
|
|
9
|
+
module.exports = function transformClerkProviderDynamic({
|
|
10
|
+
_path,
|
|
11
|
+
source
|
|
12
|
+
}, {
|
|
13
|
+
jscodeshift: j
|
|
14
|
+
}, _options) {
|
|
15
|
+
const root = j(source);
|
|
16
|
+
let dirtyFlag = false;
|
|
17
|
+
|
|
18
|
+
// Short-circuit if the import from '@clerk/nextjs' is not found
|
|
19
|
+
if (root.find(j.ImportDeclaration, {
|
|
20
|
+
source: {
|
|
21
|
+
value: '@clerk/nextjs'
|
|
22
|
+
}
|
|
23
|
+
}).size() === 0) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Find all JSXElements with the name ClerkProvider
|
|
28
|
+
root.find(j.JSXElement, {
|
|
29
|
+
openingElement: {
|
|
30
|
+
name: {
|
|
31
|
+
name: 'ClerkProvider'
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}).forEach(path => {
|
|
35
|
+
const openingElement = path.node.openingElement;
|
|
36
|
+
|
|
37
|
+
// Check if the dynamic attribute is already present
|
|
38
|
+
const hasDynamicAttribute = openingElement.attributes.some(attr => {
|
|
39
|
+
return j.JSXAttribute.check(attr) && attr.name.name === 'dynamic';
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// If dynamic attribute is not present, add it
|
|
43
|
+
if (!hasDynamicAttribute) {
|
|
44
|
+
openingElement.attributes.push(j.jsxAttribute(j.jsxIdentifier('dynamic')));
|
|
45
|
+
dirtyFlag = true;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
return dirtyFlag ? root.toSource() : undefined;
|
|
49
|
+
};
|
|
50
|
+
module.exports.parser = 'tsx';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TextInput } from '@inkjs/ui';
|
|
1
|
+
import { Spinner, StatusMessage, TextInput } from '@inkjs/ui';
|
|
2
2
|
import { Newline, Text } from 'ink';
|
|
3
3
|
import React, { useEffect, useState } from 'react';
|
|
4
4
|
import { runCodemod } from '../codemods/index.js';
|
|
@@ -6,9 +6,9 @@ import { runCodemod } from '../codemods/index.js';
|
|
|
6
6
|
/**
|
|
7
7
|
* Codemod component that allows users to run a codemod transformation on their project files.
|
|
8
8
|
*
|
|
9
|
-
* @param {Object} props
|
|
9
|
+
* @param {Object} props
|
|
10
10
|
* @param {Function} props.callback - The callback function to be called after the codemod is run.
|
|
11
|
-
* @param {string}
|
|
11
|
+
* @param {string} props.glob - The directory to scan for files in the project.
|
|
12
12
|
* @param {string} props.sdk - The SDK name to be used in the codemod.
|
|
13
13
|
* @param {string} props.transform - The transformation to be applied by the codemod.
|
|
14
14
|
*
|
|
@@ -21,8 +21,8 @@ export function Codemod(props) {
|
|
|
21
21
|
transform
|
|
22
22
|
} = props;
|
|
23
23
|
const [error, setError] = useState();
|
|
24
|
-
const [result, setResult] = useState(null);
|
|
25
24
|
const [glob, setGlob] = useState(props.glob);
|
|
25
|
+
const [result, setResult] = useState();
|
|
26
26
|
useEffect(() => {
|
|
27
27
|
if (!glob) {
|
|
28
28
|
return;
|
|
@@ -35,20 +35,24 @@ export function Codemod(props) {
|
|
|
35
35
|
callback(true);
|
|
36
36
|
});
|
|
37
37
|
}, [glob]);
|
|
38
|
-
return /*#__PURE__*/React.createElement(React.Fragment, null,
|
|
38
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, glob ? /*#__PURE__*/React.createElement(StatusMessage, {
|
|
39
|
+
variant: "success"
|
|
40
|
+
}, "Scanning for files in your project... ", glob.toString()) : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Text, null, "Where would you like for us to scan for files in your project?"), /*#__PURE__*/React.createElement(Text, {
|
|
39
41
|
color: "gray"
|
|
40
42
|
}, "(globstar syntax supported)"), glob ? /*#__PURE__*/React.createElement(Text, null, glob.toString()) : /*#__PURE__*/React.createElement(TextInput, {
|
|
41
43
|
defaultValue: "**/*",
|
|
42
44
|
onSubmit: val => {
|
|
43
45
|
setGlob(val.split(/[ ,]/));
|
|
44
46
|
}
|
|
45
|
-
})), !result && !error && glob && /*#__PURE__*/React.createElement(
|
|
46
|
-
|
|
47
|
-
}
|
|
47
|
+
})), !result && !error && glob && /*#__PURE__*/React.createElement(Spinner, {
|
|
48
|
+
label: `Running @clerk/${sdk}</Text> codemod... ${transform}`
|
|
49
|
+
}), result && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(StatusMessage, {
|
|
50
|
+
variant: "success"
|
|
51
|
+
}, "Running ", /*#__PURE__*/React.createElement(Text, {
|
|
48
52
|
bold: true
|
|
49
53
|
}, "@clerk/", sdk), " codemod... ", transform, " complete!"), /*#__PURE__*/React.createElement(Newline, null), /*#__PURE__*/React.createElement(Text, {
|
|
50
54
|
bold: true
|
|
51
|
-
}, "
|
|
55
|
+
}, "Codemod results:"), /*#__PURE__*/React.createElement(Text, {
|
|
52
56
|
color: "red"
|
|
53
57
|
}, result.error ?? 0, " errors"), /*#__PURE__*/React.createElement(Text, {
|
|
54
58
|
color: "green"
|
|
@@ -56,7 +60,7 @@ export function Codemod(props) {
|
|
|
56
60
|
color: "yellow"
|
|
57
61
|
}, result.skip ?? 0, " skipped"), /*#__PURE__*/React.createElement(Text, {
|
|
58
62
|
color: "gray"
|
|
59
|
-
}, result.nochange ?? 0, " unmodified"), result.timeElapsed && /*#__PURE__*/React.createElement(Text, null, "Time elapsed: ", result.timeElapsed)), error && /*#__PURE__*/React.createElement(Text, {
|
|
63
|
+
}, 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, {
|
|
60
64
|
color: "red"
|
|
61
65
|
}, error.message));
|
|
62
66
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Spinner, StatusMessage } from '@inkjs/ui';
|
|
2
|
+
import { execa } from 'execa';
|
|
3
|
+
import { Text } from 'ink';
|
|
4
|
+
import React, { useEffect, useState } from 'react';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Component that runs a command and handles the result.
|
|
8
|
+
*
|
|
9
|
+
* @component
|
|
10
|
+
* @param {Object} props
|
|
11
|
+
* @param {Function} props.callback - The callback function to be called after the command execution.
|
|
12
|
+
* @param {string} props.cmd - The command to execute.
|
|
13
|
+
* @param {string} props.message - The message to display while the command is running.
|
|
14
|
+
* @returns {JSX.Element} The rendered component.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* <Command cmd="echo 'hello world'" />
|
|
18
|
+
*/
|
|
19
|
+
export function Command({
|
|
20
|
+
cmd,
|
|
21
|
+
message,
|
|
22
|
+
onError,
|
|
23
|
+
onSuccess
|
|
24
|
+
}) {
|
|
25
|
+
const [error, setError] = useState();
|
|
26
|
+
const [result, setResult] = useState();
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
execa({
|
|
29
|
+
shell: true
|
|
30
|
+
})`${cmd}`.then(res => {
|
|
31
|
+
setResult(res);
|
|
32
|
+
}).catch(err => {
|
|
33
|
+
setError(err);
|
|
34
|
+
});
|
|
35
|
+
}, []);
|
|
36
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, !result && !error && /*#__PURE__*/React.createElement(Loading, {
|
|
37
|
+
cmd: cmd,
|
|
38
|
+
message: message
|
|
39
|
+
}), result ? onSuccess ? onSuccess() : /*#__PURE__*/React.createElement(StatusMessage, {
|
|
40
|
+
variant: "success"
|
|
41
|
+
}, "Successfully ran: ", /*#__PURE__*/React.createElement(Text, {
|
|
42
|
+
bold: true
|
|
43
|
+
}, cmd)) : null, error ? onError ? onError() : /*#__PURE__*/React.createElement(StatusMessage, {
|
|
44
|
+
variant: "error"
|
|
45
|
+
}, "Failed running: ", /*#__PURE__*/React.createElement(Text, {
|
|
46
|
+
bold: true
|
|
47
|
+
}, cmd)) : null);
|
|
48
|
+
}
|
|
49
|
+
function Loading({
|
|
50
|
+
cmd,
|
|
51
|
+
message
|
|
52
|
+
}) {
|
|
53
|
+
return message ? message : /*#__PURE__*/React.createElement(Spinner, {
|
|
54
|
+
label: `Running command: ${cmd}`
|
|
55
|
+
});
|
|
56
|
+
}
|
|
@@ -1,11 +1,25 @@
|
|
|
1
|
-
import { Select } from '@inkjs/ui';
|
|
2
|
-
import { execa } from 'execa';
|
|
1
|
+
import { Select, Spinner, StatusMessage } from '@inkjs/ui';
|
|
3
2
|
import { Newline, Text } from 'ink';
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
3
|
+
import Link from 'ink-link';
|
|
4
|
+
import React, { useState } from 'react';
|
|
6
5
|
import { getClerkSdkVersion } from '../util/get-clerk-version.js';
|
|
7
6
|
import { Codemod } from './Codemod.js';
|
|
7
|
+
import { Command } from './Command.js';
|
|
8
8
|
import { Header } from './Header.js';
|
|
9
|
+
import { UpgradeSDK } from './UpgradeSDK.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* SDKWorkflow component handles the upgrade process for a given SDK.
|
|
13
|
+
* It checks the current version of the SDK and provides the necessary steps
|
|
14
|
+
* to upgrade or run codemods based on the version.
|
|
15
|
+
*
|
|
16
|
+
* @component
|
|
17
|
+
* @param {Object} props
|
|
18
|
+
* @param {string} props.packageManager - The package manager to use for the upgrade, if needed.
|
|
19
|
+
* @param {string} props.sdk - The SDK to be upgraded.
|
|
20
|
+
*
|
|
21
|
+
* @returns {JSX.Element} The rendered component.
|
|
22
|
+
*/
|
|
9
23
|
export function SDKWorkflow(props) {
|
|
10
24
|
const {
|
|
11
25
|
packageManager,
|
|
@@ -14,7 +28,16 @@ export function SDKWorkflow(props) {
|
|
|
14
28
|
const [done, setDone] = useState(false);
|
|
15
29
|
const [upgradeComplete, setUpgradeComplete] = useState(false);
|
|
16
30
|
const version = getClerkSdkVersion(sdk);
|
|
17
|
-
|
|
31
|
+
if (sdk !== 'nextjs') {
|
|
32
|
+
return /*#__PURE__*/React.createElement(StatusMessage, {
|
|
33
|
+
variant: "error"
|
|
34
|
+
}, "The SDK upgrade functionality is only available for ", /*#__PURE__*/React.createElement(Text, {
|
|
35
|
+
bold: true
|
|
36
|
+
}, "@clerk/nextjs"), " at the moment.");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Right now, we only have one codemod for the `@clerk/nextjs` async request transformation
|
|
40
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(Header, null), version === 5 && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(UpgradeSDK, {
|
|
18
41
|
callback: setUpgradeComplete,
|
|
19
42
|
packageManager: packageManager,
|
|
20
43
|
sdk: sdk
|
|
@@ -42,28 +65,28 @@ export function SDKWorkflow(props) {
|
|
|
42
65
|
setDone(true);
|
|
43
66
|
}
|
|
44
67
|
}
|
|
45
|
-
})), done && /*#__PURE__*/React.createElement(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
68
|
+
})), done && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(StatusMessage, {
|
|
69
|
+
variant: "success"
|
|
70
|
+
}, "Done upgrading ", /*#__PURE__*/React.createElement(Text, {
|
|
71
|
+
bold: true
|
|
72
|
+
}, "@clerk/nextjs")), /*#__PURE__*/React.createElement(Command, {
|
|
73
|
+
cmd: 'grep -rE "import.*\\\\{.*useAuth.*\\\\}.*from.*[\'\\\\\\"]@clerk/nextjs[\'\\\\\\"]" . --exclude-dir={node_modules,dist}',
|
|
74
|
+
message: /*#__PURE__*/React.createElement(Spinner, {
|
|
75
|
+
label: 'Checking for `useAuth` usage in your project...'
|
|
76
|
+
}),
|
|
77
|
+
onError: () => null,
|
|
78
|
+
onSuccess: () => /*#__PURE__*/React.createElement(StatusMessage, {
|
|
79
|
+
variant: "warning"
|
|
80
|
+
}, /*#__PURE__*/React.createElement(Text, null, "We have detected that your application might be using the ", /*#__PURE__*/React.createElement(Text, {
|
|
81
|
+
bold: true
|
|
82
|
+
}, "useAuth"), " hook from", ' ', /*#__PURE__*/React.createElement(Text, {
|
|
83
|
+
bold: true
|
|
84
|
+
}, "@clerk/nextjs"), "."), /*#__PURE__*/React.createElement(Newline, null), /*#__PURE__*/React.createElement(Text, null, "If usages of this hook are server-side rendered, you might need to add the ", /*#__PURE__*/React.createElement(Text, {
|
|
85
|
+
bold: true
|
|
86
|
+
}, "dynamic"), ' ', "prop to your application's root ", /*#__PURE__*/React.createElement(Text, {
|
|
87
|
+
bold: true
|
|
88
|
+
}, "ClerkProvider"), "."), /*#__PURE__*/React.createElement(Newline, null), /*#__PURE__*/React.createElement(Text, null, "You can find more information about this change in the Clerk documentation at", ' ', /*#__PURE__*/React.createElement(Link, {
|
|
89
|
+
url: "https://clerk.com/docs/nextjs/rendering-modes"
|
|
90
|
+
}, "https://clerk.com/docs/nextjs/rendering-modes"), "."))
|
|
91
|
+
})));
|
|
69
92
|
}
|
package/dist/components/Scan.js
CHANGED
|
@@ -6,16 +6,17 @@ import { Newline, Text } from 'ink';
|
|
|
6
6
|
import path from 'path';
|
|
7
7
|
import React, { useEffect, useState } from 'react';
|
|
8
8
|
import ExpandableList from '../util/expandable-list.js';
|
|
9
|
-
export function Scan({
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
9
|
+
export function Scan(props) {
|
|
10
|
+
const {
|
|
11
|
+
fromVersion,
|
|
12
|
+
toVersion,
|
|
13
|
+
sdks,
|
|
14
|
+
dir,
|
|
15
|
+
ignore,
|
|
16
|
+
noWarnings,
|
|
17
|
+
uuid,
|
|
18
|
+
disableTelemetry
|
|
19
|
+
} = props;
|
|
19
20
|
// NOTE: if the difference between fromVersion and toVersion is greater than 1
|
|
20
21
|
// we need to do a little extra work here and import two matchers,
|
|
21
22
|
// sequence them after each other, and clearly mark which version migration
|
|
@@ -36,7 +37,7 @@ export function Scan({
|
|
|
36
37
|
// { sdkName: [{ title: 'x', matcher: /x/, slug: 'x', ... }] }
|
|
37
38
|
useEffect(() => {
|
|
38
39
|
setStatus(`Loading data for ${toVersion} migration`);
|
|
39
|
-
import(
|
|
40
|
+
import(`../versions/${toVersion}/index.js`).then(version => {
|
|
40
41
|
setMatchers(sdks.reduce((m, sdk) => {
|
|
41
42
|
m[sdk] = version.default[sdk];
|
|
42
43
|
return m;
|
|
@@ -49,12 +50,9 @@ export function Scan({
|
|
|
49
50
|
// result = `files` set to format: ['/filename', '/other/filename']
|
|
50
51
|
useEffect(() => {
|
|
51
52
|
setStatus('Collecting files to scan');
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
);
|
|
56
|
-
globby(convertPathToPattern(path.resolve(dir)), {
|
|
57
|
-
ignore: ignore.filter(Boolean)
|
|
53
|
+
const pattern = convertPathToPattern(path.resolve(dir));
|
|
54
|
+
globby(pattern, {
|
|
55
|
+
ignore: ['node_modules/**', '**/node_modules/**', '.git/**', 'package.json', '**/package.json', 'package-lock.json', '**/package-lock.json', 'yarn.lock', '**/yarn.lock', 'pnpm-lock.yaml', '**/pnpm-lock.yaml', '**/*.(png|webp|svg|gif|jpg|jpeg)+', '**/*.(mp4|mkv|wmv|m4v|mov|avi|flv|webm|flac|mka|m4a|aac|ogg)+', ...ignore].filter(Boolean)
|
|
58
56
|
}).then(files => {
|
|
59
57
|
setFiles(files);
|
|
60
58
|
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Spinner, StatusMessage } from '@inkjs/ui';
|
|
2
|
+
import { execa } from 'execa';
|
|
3
|
+
import { existsSync } from 'fs';
|
|
4
|
+
import { Text } from 'ink';
|
|
5
|
+
import React, { useEffect, useState } from 'react';
|
|
6
|
+
function detectPackageManager() {
|
|
7
|
+
if (existsSync('package-lock.json')) {
|
|
8
|
+
return 'npm';
|
|
9
|
+
} else if (existsSync('yarn.lock')) {
|
|
10
|
+
return 'yarn';
|
|
11
|
+
} else if (existsSync('pnpm-lock.yaml')) {
|
|
12
|
+
return 'pnpm';
|
|
13
|
+
} else {
|
|
14
|
+
return 'npm';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function upgradeCommand(sdk, packageManager) {
|
|
18
|
+
switch (packageManager || detectPackageManager()) {
|
|
19
|
+
case 'yarn':
|
|
20
|
+
return `yarn add @clerk/${sdk}@latest`;
|
|
21
|
+
case 'pnpm':
|
|
22
|
+
return `pnpm add @clerk/${sdk}@latest`;
|
|
23
|
+
default:
|
|
24
|
+
return `npm install @clerk/${sdk}@latest`;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Component that runs an upgrade command for a given SDK and handles the result.
|
|
30
|
+
*
|
|
31
|
+
* @component
|
|
32
|
+
* @param {Object} props
|
|
33
|
+
* @param {Function} props.callback - The callback function to be called after the command execution.
|
|
34
|
+
* @param {string} props.packageManager - The package manager used in the project in case we cannot detect it automatically.
|
|
35
|
+
* @param {string} props.sdk - The SDK for which the upgrade command is run.
|
|
36
|
+
* @returns {JSX.Element} The rendered component.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* <UpgradeCommand sdk="example-sdk" callback={handleUpgrade} />
|
|
40
|
+
*/
|
|
41
|
+
export function UpgradeSDK({
|
|
42
|
+
callback,
|
|
43
|
+
packageManager,
|
|
44
|
+
sdk
|
|
45
|
+
}) {
|
|
46
|
+
const [error, setError] = useState();
|
|
47
|
+
const [result, setResult] = useState();
|
|
48
|
+
const command = upgradeCommand(sdk, packageManager);
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
execa({
|
|
51
|
+
shell: true
|
|
52
|
+
})`${command}`.then(res => {
|
|
53
|
+
setResult(res);
|
|
54
|
+
callback(true);
|
|
55
|
+
}).catch(err => {
|
|
56
|
+
setError(err);
|
|
57
|
+
});
|
|
58
|
+
}, [command]);
|
|
59
|
+
return /*#__PURE__*/React.createElement(React.Fragment, null, !result && !error && /*#__PURE__*/React.createElement(Spinner, {
|
|
60
|
+
label: `Running upgrade command: ${command}`
|
|
61
|
+
}), result && /*#__PURE__*/React.createElement(StatusMessage, {
|
|
62
|
+
variant: "success"
|
|
63
|
+
}, /*#__PURE__*/React.createElement(Text, {
|
|
64
|
+
bold: true
|
|
65
|
+
}, "@clerk/", sdk), " upgraded successfully to ", /*#__PURE__*/React.createElement(Text, {
|
|
66
|
+
bold: true
|
|
67
|
+
}, "latest!")), error && /*#__PURE__*/React.createElement(StatusMessage, {
|
|
68
|
+
variant: "error"
|
|
69
|
+
}, "Upgrade failed!"));
|
|
70
|
+
}
|
package/package.json
CHANGED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'fs';
|
|
2
|
-
export function detectPackageManager() {
|
|
3
|
-
if (existsSync('package-lock.json')) {
|
|
4
|
-
return 'npm';
|
|
5
|
-
} else if (existsSync('yarn.lock')) {
|
|
6
|
-
return 'yarn';
|
|
7
|
-
} else if (existsSync('pnpm-lock.yaml')) {
|
|
8
|
-
return 'pnpm';
|
|
9
|
-
} else {
|
|
10
|
-
return 'npm';
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
export function getUpgradeCommand(sdk, packageManager) {
|
|
14
|
-
switch (packageManager || detectPackageManager()) {
|
|
15
|
-
case 'yarn':
|
|
16
|
-
return `yarn add @clerk/${sdk}@latest`;
|
|
17
|
-
case 'pnpm':
|
|
18
|
-
return `pnpm add @clerk/${sdk}@latest`;
|
|
19
|
-
default:
|
|
20
|
-
return `npm install @clerk/${sdk}@latest`;
|
|
21
|
-
}
|
|
22
|
-
}
|