@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,5 @@
1
+ {
2
+ "name": "test-expo-old",
3
+ "lockfileVersion": 3
4
+ }
5
+
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "test-expo-old",
3
+ "version": "1.0.0",
4
+ "dependencies": {
5
+ "@clerk/clerk-expo": "^2.0.0",
6
+ "expo": "^50.0.0",
7
+ "react": "^18.0.0",
8
+ "react-native": "^0.73.0"
9
+ }
10
+ }
@@ -0,0 +1,14 @@
1
+ import { ClerkProvider, useAuth } from '@clerk/clerk-expo';
2
+
3
+ export default function App() {
4
+ return (
5
+ <ClerkProvider publishableKey='pk_test_xxx'>
6
+ <AuthStatus />
7
+ </ClerkProvider>
8
+ );
9
+ }
10
+
11
+ function AuthStatus() {
12
+ const { isSignedIn } = useAuth();
13
+ return <Text>{isSignedIn ? 'Signed in' : 'Signed out'}</Text>;
14
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "test-nextjs-v6",
3
+ "version": "1.0.0",
4
+ "dependencies": {
5
+ "@clerk/nextjs": "^6.0.0",
6
+ "next": "^14.0.0",
7
+ "react": "^18.0.0"
8
+ }
9
+ }
@@ -0,0 +1,2 @@
1
+ lockfileVersion: '9.0'
2
+
@@ -0,0 +1,17 @@
1
+ import { ClerkProvider, useAuth, useUser } from '@clerk/nextjs';
2
+ import { dark } from '@clerk/nextjs/themes';
3
+
4
+ export default function App({ children }) {
5
+ return <ClerkProvider appearance={{ baseTheme: dark }}>{children}</ClerkProvider>;
6
+ }
7
+
8
+ export function UserProfile() {
9
+ const { isSignedIn } = useAuth();
10
+ const { user } = useUser();
11
+
12
+ if (!isSignedIn) {
13
+ return <div>Not signed in</div>;
14
+ }
15
+
16
+ return <div>Hello, {user?.firstName}</div>;
17
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "test-nextjs-v7",
3
+ "version": "1.0.0",
4
+ "dependencies": {
5
+ "@clerk/nextjs": "^7.0.0",
6
+ "next": "^14.0.0",
7
+ "react": "^18.0.0"
8
+ }
9
+ }
@@ -0,0 +1,2 @@
1
+ lockfileVersion: '9.0'
2
+
@@ -0,0 +1,16 @@
1
+ import { ClerkProvider, useAuth, useUser } from '@clerk/nextjs';
2
+
3
+ export default function App({ children }) {
4
+ return <ClerkProvider>{children}</ClerkProvider>;
5
+ }
6
+
7
+ export function UserProfile() {
8
+ const { isSignedIn } = useAuth();
9
+ const { user } = useUser();
10
+
11
+ if (!isSignedIn) {
12
+ return <div>Not signed in</div>;
13
+ }
14
+
15
+ return <div>Hello, {user?.firstName}</div>;
16
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "test-no-clerk",
3
+ "version": "1.0.0",
4
+ "dependencies": {
5
+ "react": "^18.0.0"
6
+ }
7
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "test-react-v6",
3
+ "version": "1.0.0",
4
+ "dependencies": {
5
+ "@clerk/clerk-react": "^5.0.0",
6
+ "react": "^18.0.0"
7
+ }
8
+ }
@@ -0,0 +1,19 @@
1
+ import { ClerkProvider, useUser } from '@clerk/react';
2
+
3
+ export default function App() {
4
+ return (
5
+ <ClerkProvider publishableKey='pk_test_xxx'>
6
+ <UserInfo />
7
+ </ClerkProvider>
8
+ );
9
+ }
10
+
11
+ function UserInfo() {
12
+ const { user, isSignedIn } = useUser();
13
+
14
+ if (!isSignedIn) {
15
+ return <div>Please sign in</div>;
16
+ }
17
+
18
+ return <div>Welcome, {user?.firstName}</div>;
19
+ }
@@ -0,0 +1,2 @@
1
+ # yarn lockfile v1
2
+
@@ -0,0 +1,56 @@
1
+ import fs from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
+ const FIXTURES_DIR = path.join(__dirname, '..', 'fixtures');
7
+ export function getFixturePath(fixtureName) {
8
+ return path.join(FIXTURES_DIR, fixtureName);
9
+ }
10
+ export function createTempFixture(fixtureName) {
11
+ const sourcePath = getFixturePath(fixtureName);
12
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), `clerk-upgrade-test-${fixtureName}-`));
13
+ copyDirSync(sourcePath, tempDir);
14
+ return {
15
+ path: tempDir,
16
+ cleanup() {
17
+ fs.rmSync(tempDir, {
18
+ recursive: true,
19
+ force: true
20
+ });
21
+ }
22
+ };
23
+ }
24
+ function copyDirSync(src, dest) {
25
+ fs.mkdirSync(dest, {
26
+ recursive: true
27
+ });
28
+ const entries = fs.readdirSync(src, {
29
+ withFileTypes: true
30
+ });
31
+ for (const entry of entries) {
32
+ const srcPath = path.join(src, entry.name);
33
+ const destPath = path.join(dest, entry.name);
34
+ if (entry.isDirectory()) {
35
+ copyDirSync(srcPath, destPath);
36
+ } else {
37
+ fs.copyFileSync(srcPath, destPath);
38
+ }
39
+ }
40
+ }
41
+ export function readFixtureFile(fixtureName, filePath) {
42
+ return fs.readFileSync(path.join(getFixturePath(fixtureName), filePath), 'utf8');
43
+ }
44
+ export function writeFixtureFile(tempPath, filePath, content) {
45
+ const fullPath = path.join(tempPath, filePath);
46
+ fs.mkdirSync(path.dirname(fullPath), {
47
+ recursive: true
48
+ });
49
+ fs.writeFileSync(fullPath, content, 'utf8');
50
+ }
51
+ export function readTempFile(tempPath, filePath) {
52
+ return fs.readFileSync(path.join(tempPath, filePath), 'utf8');
53
+ }
54
+ export function fileExists(tempPath, filePath) {
55
+ return fs.existsSync(path.join(tempPath, filePath));
56
+ }
@@ -0,0 +1,230 @@
1
+ import { spawn } from 'node:child_process';
2
+ import path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
5
+ import { createTempFixture, getFixturePath } from '../helpers/create-fixture.js';
6
+
7
+ // Toggle this to true to debug the CLI output during the test run
8
+ const DEBUG_OUTPUT = false;
9
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
10
+ const CLI_PATH = path.resolve(__dirname, '../../cli.js');
11
+ function runCli(args = [], options = {}) {
12
+ return new Promise((resolve, reject) => {
13
+ const child = spawn('node', [CLI_PATH, ...args], {
14
+ cwd: options.cwd || process.cwd(),
15
+ env: {
16
+ ...process.env,
17
+ FORCE_COLOR: '0',
18
+ NO_COLOR: '1'
19
+ },
20
+ stdio: ['pipe', 'pipe', 'pipe']
21
+ });
22
+ let stdout = '';
23
+ let stderr = '';
24
+ child.stdout.on('data', data => {
25
+ stdout += data.toString();
26
+ if (DEBUG_OUTPUT) {
27
+ console.log(data.toString());
28
+ }
29
+ });
30
+ child.stderr.on('data', data => {
31
+ stderr += data.toString();
32
+ if (DEBUG_OUTPUT) {
33
+ console.error(data.toString());
34
+ }
35
+ });
36
+
37
+ // Send input if provided (for interactive prompts)
38
+ if (options.input) {
39
+ child.stdin.write(options.input);
40
+ child.stdin.end();
41
+ }
42
+
43
+ // Set timeout to kill the process
44
+ const timeout = setTimeout(() => {
45
+ child.kill('SIGTERM');
46
+ resolve({
47
+ stdout,
48
+ stderr,
49
+ exitCode: null,
50
+ timedOut: true
51
+ });
52
+ }, options.timeout || 10000);
53
+ child.on('close', exitCode => {
54
+ clearTimeout(timeout);
55
+ resolve({
56
+ stdout,
57
+ stderr,
58
+ exitCode,
59
+ timedOut: false
60
+ });
61
+ });
62
+ child.on('error', err => {
63
+ clearTimeout(timeout);
64
+ reject(err);
65
+ });
66
+ });
67
+ }
68
+ describe('CLI Integration', () => {
69
+ describe('--help flag', () => {
70
+ it('displays help text', async () => {
71
+ const result = await runCli(['--help']);
72
+ expect(result.stdout).toContain('Usage');
73
+ expect(result.stdout).toContain('npx @clerk/upgrade');
74
+ expect(result.stdout).toContain('--sdk');
75
+ expect(result.stdout).toContain('--dir');
76
+ expect(result.stdout).toContain('--dry-run');
77
+ expect(result.exitCode).toBe(0);
78
+ });
79
+ });
80
+ describe('--version flag', () => {
81
+ it('displays version', async () => {
82
+ const result = await runCli(['--version']);
83
+ expect(result.stdout).toMatch(/\d+\.\d+\.\d+/);
84
+ expect(result.exitCode).toBe(0);
85
+ });
86
+ });
87
+ describe('SDK Detection', () => {
88
+ it('detects nextjs SDK from project directory', async () => {
89
+ const dir = getFixturePath('nextjs-v6');
90
+ const result = await runCli(['--dir', dir, '--dry-run', '--skip-codemods'], {
91
+ timeout: 15000
92
+ });
93
+
94
+ // Combine stdout and stderr for full output
95
+ const output = result.stdout + result.stderr;
96
+ expect(output).toContain('@clerk/nextjs');
97
+ expect(output).toContain('dry run');
98
+ });
99
+ it('detects nextjs v7 as already upgraded', async () => {
100
+ const dir = getFixturePath('nextjs-v7');
101
+ const result = await runCli(['--dir', dir, '--dry-run', '--skip-codemods'], {
102
+ timeout: 15000
103
+ });
104
+ expect(result.stdout).toContain('@clerk/nextjs');
105
+ expect(result.stdout).toContain('already on the latest');
106
+ });
107
+ it('errors when SDK not detected and not provided in non-interactive mode', async () => {
108
+ const dir = getFixturePath('no-clerk');
109
+ const result = await runCli(['--dir', dir, '--dry-run', '--skip-codemods'], {
110
+ timeout: 5000
111
+ });
112
+
113
+ // Error messages go to stderr via console.error
114
+ const output = result.stdout + result.stderr;
115
+ expect(output).toContain('Could not detect Clerk SDK');
116
+ expect(output).toContain('--sdk');
117
+ expect(result.exitCode).toBe(1);
118
+ });
119
+ });
120
+ describe('--sdk flag', () => {
121
+ it('accepts explicit SDK specification', async () => {
122
+ const dir = getFixturePath('nextjs-v6');
123
+ const result = await runCli(['--dir', dir, '--sdk', 'nextjs', '--dry-run', '--skip-codemods'], {
124
+ timeout: 15000
125
+ });
126
+ expect(result.stdout).toContain('@clerk/nextjs');
127
+ });
128
+ it('accepts @clerk/ prefixed SDK name', async () => {
129
+ const dir = getFixturePath('nextjs-v6');
130
+ const result = await runCli(['--dir', dir, '--sdk', '@clerk/nextjs', '--dry-run', '--skip-codemods'], {
131
+ timeout: 15000
132
+ });
133
+ expect(result.stdout).toContain('@clerk/nextjs');
134
+ });
135
+ });
136
+ describe('--dry-run flag', () => {
137
+ let fixture;
138
+ beforeEach(() => {
139
+ fixture = createTempFixture('nextjs-v6');
140
+ });
141
+ afterEach(() => {
142
+ fixture?.cleanup();
143
+ });
144
+ it('shows what would be done without making changes', async () => {
145
+ const result = await runCli(['--dir', fixture.path, '--dry-run', '--skip-codemods'], {
146
+ timeout: 15000
147
+ });
148
+ expect(result.stdout).toContain('[dry run]');
149
+ });
150
+ it('does not modify package.json in dry-run mode', async () => {
151
+ const fs = await import('node:fs');
152
+ const pkgBefore = fs.readFileSync(path.join(fixture.path, 'package.json'), 'utf8');
153
+ await runCli(['--dir', fixture.path, '--dry-run', '--skip-codemods'], {
154
+ timeout: 15000
155
+ });
156
+ const pkgAfter = fs.readFileSync(path.join(fixture.path, 'package.json'), 'utf8');
157
+ expect(pkgAfter).toBe(pkgBefore);
158
+ });
159
+ });
160
+ describe('Version Display', () => {
161
+ it('shows current version in output', async () => {
162
+ const dir = getFixturePath('nextjs-v6');
163
+ const result = await runCli(['--dir', dir, '--dry-run', '--skip-codemods'], {
164
+ timeout: 15000
165
+ });
166
+ expect(result.stdout).toContain('v6');
167
+ });
168
+ it('shows upgrade path in output', async () => {
169
+ const dir = getFixturePath('nextjs-v6');
170
+ const result = await runCli(['--dir', dir, '--dry-run', '--skip-codemods'], {
171
+ timeout: 15000
172
+ });
173
+ expect(result.stdout).toContain('v6 → v7');
174
+ });
175
+ });
176
+ describe('Package Manager Detection', () => {
177
+ it('detects pnpm from fixture', async () => {
178
+ const dir = getFixturePath('nextjs-v6');
179
+ const result = await runCli(['--dir', dir, '--dry-run', '--skip-codemods'], {
180
+ timeout: 15000
181
+ });
182
+ expect(result.stdout).toContain('pnpm');
183
+ });
184
+ it('detects yarn from fixture', async () => {
185
+ const dir = getFixturePath('react-v6');
186
+ const result = await runCli(['--dir', dir, '--dry-run', '--skip-codemods'], {
187
+ timeout: 15000
188
+ });
189
+ expect(result.stdout).toMatch(/yarn/i);
190
+ });
191
+ it('detects npm from fixture', async () => {
192
+ const dir = getFixturePath('expo-old-package');
193
+ const result = await runCli(['--dir', dir, '--dry-run', '--skip-codemods'], {
194
+ timeout: 15000
195
+ });
196
+ expect(result.stdout).toMatch(/npm/i);
197
+ });
198
+ });
199
+ describe('Legacy Package Names', () => {
200
+ it('handles @clerk/clerk-react legacy package', async () => {
201
+ const dir = getFixturePath('react-v6');
202
+ const result = await runCli(['--dir', dir, '--dry-run', '--skip-codemods'], {
203
+ timeout: 15000
204
+ });
205
+ expect(result.stdout).toContain('@clerk/react');
206
+ });
207
+ it('handles @clerk/clerk-expo legacy package', async () => {
208
+ const dir = getFixturePath('expo-old-package');
209
+ const result = await runCli(['--dir', dir, '--dry-run', '--skip-codemods'], {
210
+ timeout: 15000
211
+ });
212
+ expect(result.stdout).toContain('@clerk/expo');
213
+ });
214
+ });
215
+ describe('Codemods', () => {
216
+ let fixture;
217
+ beforeEach(() => {
218
+ fixture = createTempFixture('nextjs-v6');
219
+ });
220
+ afterEach(() => {
221
+ fixture?.cleanup();
222
+ });
223
+ it('lists codemods that would run in dry-run mode', async () => {
224
+ const result = await runCli(['--dir', fixture.path, '--dry-run', '--skip-codemods'], {
225
+ timeout: 15000
226
+ });
227
+ expect(result.stdout).toContain('codemod');
228
+ });
229
+ });
230
+ });
@@ -0,0 +1,76 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { getOldPackageName, getTargetPackageName, loadConfig } from '../../config.js';
3
+ describe('loadConfig', () => {
4
+ it('returns config with needsUpgrade: true for nextjs v6', async () => {
5
+ const config = await loadConfig('nextjs', 6);
6
+ expect(config).not.toBeNull();
7
+ expect(config.id).toBe('core-3');
8
+ expect(config.needsUpgrade).toBe(true);
9
+ expect(config.alreadyUpgraded).toBe(false);
10
+ });
11
+ it('returns config with alreadyUpgraded: true for nextjs v7', async () => {
12
+ const config = await loadConfig('nextjs', 7);
13
+ expect(config).not.toBeNull();
14
+ expect(config.id).toBe('core-3');
15
+ expect(config.needsUpgrade).toBe(false);
16
+ expect(config.alreadyUpgraded).toBe(true);
17
+ });
18
+ it('returns config with needsUpgrade: true for react v6', async () => {
19
+ const config = await loadConfig('react', 6);
20
+ expect(config).not.toBeNull();
21
+ expect(config.needsUpgrade).toBe(true);
22
+ });
23
+ it('returns config with needsUpgrade: true for expo v2', async () => {
24
+ const config = await loadConfig('expo', 2);
25
+ expect(config).not.toBeNull();
26
+ expect(config.needsUpgrade).toBe(true);
27
+ });
28
+ it('returns null for unsupported SDK version (too old)', async () => {
29
+ const config = await loadConfig('nextjs', 4);
30
+ expect(config).toBeNull();
31
+ });
32
+ it('loads codemods array from config', async () => {
33
+ const config = await loadConfig('nextjs', 6);
34
+ expect(config.codemods).toBeDefined();
35
+ expect(Array.isArray(config.codemods)).toBe(true);
36
+ expect(config.codemods.length).toBeGreaterThan(0);
37
+ });
38
+ it('loads changes array from config', async () => {
39
+ const config = await loadConfig('nextjs', 6);
40
+ expect(config.changes).toBeDefined();
41
+ expect(Array.isArray(config.changes)).toBe(true);
42
+ });
43
+ it('includes docsUrl in config', async () => {
44
+ const config = await loadConfig('nextjs', 6);
45
+ expect(config.docsUrl).toBeDefined();
46
+ expect(config.docsUrl).toContain('clerk.com');
47
+ });
48
+ });
49
+ describe('getTargetPackageName', () => {
50
+ it('returns @clerk/react for react sdk', () => {
51
+ expect(getTargetPackageName('react')).toBe('@clerk/react');
52
+ });
53
+ it('returns @clerk/react for clerk-react sdk', () => {
54
+ expect(getTargetPackageName('clerk-react')).toBe('@clerk/react');
55
+ });
56
+ it('returns @clerk/expo for expo sdk', () => {
57
+ expect(getTargetPackageName('expo')).toBe('@clerk/expo');
58
+ });
59
+ it('returns @clerk/expo for clerk-expo sdk', () => {
60
+ expect(getTargetPackageName('clerk-expo')).toBe('@clerk/expo');
61
+ });
62
+ it('returns @clerk/nextjs for nextjs sdk', () => {
63
+ expect(getTargetPackageName('nextjs')).toBe('@clerk/nextjs');
64
+ });
65
+ });
66
+ describe('getOldPackageName', () => {
67
+ it('returns @clerk/clerk-react for react sdk', () => {
68
+ expect(getOldPackageName('react')).toBe('@clerk/clerk-react');
69
+ });
70
+ it('returns @clerk/clerk-expo for expo sdk', () => {
71
+ expect(getOldPackageName('expo')).toBe('@clerk/clerk-expo');
72
+ });
73
+ it('returns null for nextjs sdk (no rename)', () => {
74
+ expect(getOldPackageName('nextjs')).toBeNull();
75
+ });
76
+ });
@@ -0,0 +1,100 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { detectSdk, getMajorVersion, getSdkVersion, normalizeSdkName } from '../../util/detect-sdk.js';
3
+ import { detectPackageManager } from '../../util/package-manager.js';
4
+ import { getFixturePath } from '../helpers/create-fixture.js';
5
+ describe('detectSdk', () => {
6
+ it('detects @clerk/nextjs from package.json', () => {
7
+ const sdk = detectSdk(getFixturePath('nextjs-v6'));
8
+ expect(sdk).toBe('nextjs');
9
+ });
10
+ it('detects @clerk/nextjs v7 from package.json', () => {
11
+ const sdk = detectSdk(getFixturePath('nextjs-v7'));
12
+ expect(sdk).toBe('nextjs');
13
+ });
14
+ it('detects @clerk/clerk-react (legacy name) from package.json', () => {
15
+ const sdk = detectSdk(getFixturePath('react-v6'));
16
+ expect(sdk).toBe('react');
17
+ });
18
+ it('detects @clerk/clerk-expo (legacy name) from package.json', () => {
19
+ const sdk = detectSdk(getFixturePath('expo-old-package'));
20
+ expect(sdk).toBe('expo');
21
+ });
22
+ it('returns null when no Clerk SDK is found', () => {
23
+ const sdk = detectSdk(getFixturePath('no-clerk'));
24
+ expect(sdk).toBeNull();
25
+ });
26
+ });
27
+ describe('getSdkVersion', () => {
28
+ it('returns major version 6 for nextjs-v6 fixture', () => {
29
+ const version = getSdkVersion('nextjs', getFixturePath('nextjs-v6'));
30
+ expect(version).toBe(6);
31
+ });
32
+ it('returns major version 7 for nextjs-v7 fixture', () => {
33
+ const version = getSdkVersion('nextjs', getFixturePath('nextjs-v7'));
34
+ expect(version).toBe(7);
35
+ });
36
+ it('returns major version 5 for clerk-react fixture', () => {
37
+ const version = getSdkVersion('clerk-react', getFixturePath('react-v6'));
38
+ expect(version).toBe(5);
39
+ });
40
+ it('returns major version 2 for clerk-expo fixture', () => {
41
+ const version = getSdkVersion('clerk-expo', getFixturePath('expo-old-package'));
42
+ expect(version).toBe(2);
43
+ });
44
+ it('returns null when SDK is not found', () => {
45
+ const version = getSdkVersion('nextjs', getFixturePath('no-clerk'));
46
+ expect(version).toBeNull();
47
+ });
48
+ });
49
+ describe('getMajorVersion', () => {
50
+ it('parses ^6.0.0 as version 6', () => {
51
+ expect(getMajorVersion('^6.0.0')).toBe(6);
52
+ });
53
+ it('parses ~7.1.2 as version 7', () => {
54
+ expect(getMajorVersion('~7.1.2')).toBe(7);
55
+ });
56
+ it('parses 5.0.0 as version 5', () => {
57
+ expect(getMajorVersion('5.0.0')).toBe(5);
58
+ });
59
+ it('parses 14.2.3 as version 14', () => {
60
+ expect(getMajorVersion('14.2.3')).toBe(14);
61
+ });
62
+ it('returns null for invalid semver', () => {
63
+ expect(getMajorVersion('invalid')).toBeNull();
64
+ });
65
+ });
66
+ describe('normalizeSdkName', () => {
67
+ it('returns null for null input', () => {
68
+ expect(normalizeSdkName(null)).toBeNull();
69
+ });
70
+ it('strips @clerk/ prefix', () => {
71
+ expect(normalizeSdkName('@clerk/nextjs')).toBe('nextjs');
72
+ });
73
+ it('converts clerk-react to react', () => {
74
+ expect(normalizeSdkName('clerk-react')).toBe('react');
75
+ });
76
+ it('converts clerk-expo to expo', () => {
77
+ expect(normalizeSdkName('clerk-expo')).toBe('expo');
78
+ });
79
+ it('returns name unchanged for standard names', () => {
80
+ expect(normalizeSdkName('nextjs')).toBe('nextjs');
81
+ });
82
+ });
83
+ describe('detectPackageManager', () => {
84
+ it('detects pnpm from pnpm-lock.yaml', () => {
85
+ const pm = detectPackageManager(getFixturePath('nextjs-v6'));
86
+ expect(pm).toBe('pnpm');
87
+ });
88
+ it('detects yarn from yarn.lock', () => {
89
+ const pm = detectPackageManager(getFixturePath('react-v6'));
90
+ expect(pm).toBe('yarn');
91
+ });
92
+ it('detects npm from package-lock.json', () => {
93
+ const pm = detectPackageManager(getFixturePath('expo-old-package'));
94
+ expect(pm).toBe('npm');
95
+ });
96
+ it('defaults to npm when no lock file exists', () => {
97
+ const pm = detectPackageManager(getFixturePath('no-clerk'));
98
+ expect(pm).toBe('npm');
99
+ });
100
+ });