@clerk/upgrade 2.0.0-snapshot.v20251204175016 → 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.
- package/dist/__tests__/fixtures/expo-old-package/package-lock.json +5 -0
- package/dist/__tests__/fixtures/expo-old-package/package.json +10 -0
- package/dist/__tests__/fixtures/expo-old-package/src/App.tsx +14 -0
- package/dist/__tests__/fixtures/nextjs-v6/package.json +9 -0
- package/dist/__tests__/fixtures/nextjs-v6/pnpm-lock.yaml +2 -0
- package/dist/__tests__/fixtures/nextjs-v6/src/app.tsx +17 -0
- package/dist/__tests__/fixtures/nextjs-v7/package.json +9 -0
- package/dist/__tests__/fixtures/nextjs-v7/pnpm-lock.yaml +2 -0
- package/dist/__tests__/fixtures/nextjs-v7/src/app.tsx +16 -0
- package/dist/__tests__/fixtures/no-clerk/package.json +7 -0
- package/dist/__tests__/fixtures/react-v6/package.json +8 -0
- package/dist/__tests__/fixtures/react-v6/src/App.tsx +19 -0
- package/dist/__tests__/fixtures/react-v6/yarn.lock +2 -0
- package/dist/__tests__/helpers/create-fixture.js +56 -0
- package/dist/__tests__/integration/cli.test.js +230 -0
- package/dist/__tests__/integration/config.test.js +76 -0
- package/dist/__tests__/integration/detect-sdk.test.js +100 -0
- package/dist/__tests__/integration/runner.test.js +79 -0
- package/dist/cli.js +159 -45
- package/dist/codemods/__tests__/__fixtures__/transform-align-experimental-unstable-prefixes.fixtures.js +68 -0
- package/dist/codemods/__tests__/__fixtures__/transform-appearance-layout-to-options.fixtures.js +9 -0
- package/dist/codemods/__tests__/__fixtures__/transform-clerk-react-v6.fixtures.js +13 -0
- package/dist/codemods/__tests__/__fixtures__/transform-remove-deprecated-appearance-props.fixtures.js +63 -0
- package/dist/codemods/__tests__/__fixtures__/transform-themes-to-ui-themes.fixtures.js +41 -0
- package/dist/codemods/__tests__/transform-align-experimental-unstable-prefixes.test.js +15 -0
- package/dist/codemods/__tests__/transform-appearance-layout-to-options.test.js +15 -0
- package/dist/codemods/__tests__/transform-remove-deprecated-appearance-props.test.js +15 -0
- package/dist/codemods/__tests__/transform-themes-to-ui-themes.test.js +15 -0
- package/dist/codemods/index.js +67 -13
- package/dist/codemods/transform-align-experimental-unstable-prefixes.cjs +400 -0
- package/dist/codemods/transform-appearance-layout-to-options.cjs +65 -0
- package/dist/codemods/transform-clerk-react-v6.cjs +15 -7
- package/dist/codemods/transform-remove-deprecated-appearance-props.cjs +109 -0
- package/dist/codemods/transform-remove-deprecated-props.cjs +11 -32
- package/dist/codemods/transform-themes-to-ui-themes.cjs +65 -0
- package/dist/config.js +122 -0
- package/dist/render.js +164 -0
- package/dist/runner.js +98 -0
- package/dist/util/detect-sdk.js +125 -0
- package/dist/util/package-manager.js +94 -0
- package/dist/versions/core-3/changes/clerk-expo-package-rename.md +23 -0
- package/dist/versions/core-3/changes/clerk-react-package-rename.md +23 -0
- package/dist/versions/core-3/index.js +40 -0
- package/package.json +2 -8
- package/dist/app.js +0 -177
- package/dist/components/Codemod.js +0 -149
- package/dist/components/Command.js +0 -56
- package/dist/components/Header.js +0 -11
- package/dist/components/SDKWorkflow.js +0 -278
- package/dist/components/Scan.js +0 -180
- package/dist/components/UpgradeSDK.js +0 -116
- package/dist/util/expandable-list.js +0 -173
- package/dist/util/get-clerk-version.js +0 -22
- package/dist/util/guess-framework.js +0 -69
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { loadConfig } from '../../config.js';
|
|
3
|
+
import { runScans } from '../../runner.js';
|
|
4
|
+
import { createTempFixture } from '../helpers/create-fixture.js';
|
|
5
|
+
vi.mock('../../render.js', () => ({
|
|
6
|
+
colors: {
|
|
7
|
+
reset: '',
|
|
8
|
+
bold: '',
|
|
9
|
+
yellow: '',
|
|
10
|
+
gray: ''
|
|
11
|
+
},
|
|
12
|
+
createSpinner: vi.fn(() => ({
|
|
13
|
+
update: vi.fn(),
|
|
14
|
+
stop: vi.fn(),
|
|
15
|
+
success: vi.fn(),
|
|
16
|
+
error: vi.fn()
|
|
17
|
+
})),
|
|
18
|
+
promptText: vi.fn((msg, defaultValue) => defaultValue),
|
|
19
|
+
renderCodemodResults: vi.fn(),
|
|
20
|
+
renderText: vi.fn()
|
|
21
|
+
}));
|
|
22
|
+
describe('runScans', () => {
|
|
23
|
+
let fixture;
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
fixture = createTempFixture('nextjs-v6');
|
|
26
|
+
});
|
|
27
|
+
afterEach(() => {
|
|
28
|
+
fixture?.cleanup();
|
|
29
|
+
});
|
|
30
|
+
it('finds patterns in fixture files', async () => {
|
|
31
|
+
const config = await loadConfig('nextjs', 6);
|
|
32
|
+
const options = {
|
|
33
|
+
dir: fixture.path,
|
|
34
|
+
ignore: []
|
|
35
|
+
};
|
|
36
|
+
const results = await runScans(config, 'nextjs', options);
|
|
37
|
+
expect(Array.isArray(results)).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
it('returns empty array when no matchers match', async () => {
|
|
40
|
+
const config = await loadConfig('nextjs', 6);
|
|
41
|
+
config.changes = [];
|
|
42
|
+
const options = {
|
|
43
|
+
dir: fixture.path,
|
|
44
|
+
ignore: []
|
|
45
|
+
};
|
|
46
|
+
const results = await runScans(config, 'nextjs', options);
|
|
47
|
+
expect(results).toEqual([]);
|
|
48
|
+
});
|
|
49
|
+
it('respects ignore patterns', async () => {
|
|
50
|
+
const config = await loadConfig('nextjs', 6);
|
|
51
|
+
const options = {
|
|
52
|
+
dir: fixture.path,
|
|
53
|
+
ignore: ['**/src/**']
|
|
54
|
+
};
|
|
55
|
+
const results = await runScans(config, 'nextjs', options);
|
|
56
|
+
expect(Array.isArray(results)).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
describe('runScans with theme imports', () => {
|
|
60
|
+
let fixture;
|
|
61
|
+
beforeEach(() => {
|
|
62
|
+
fixture = createTempFixture('nextjs-v6');
|
|
63
|
+
});
|
|
64
|
+
afterEach(() => {
|
|
65
|
+
fixture?.cleanup();
|
|
66
|
+
});
|
|
67
|
+
it('detects theme imports from @clerk/nextjs/themes', async () => {
|
|
68
|
+
const config = await loadConfig('nextjs', 6);
|
|
69
|
+
const options = {
|
|
70
|
+
dir: fixture.path,
|
|
71
|
+
ignore: []
|
|
72
|
+
};
|
|
73
|
+
const results = await runScans(config, 'nextjs', options);
|
|
74
|
+
const themeChange = results.find(r => r.title?.includes('Theme') || r.docsAnchor?.includes('theme'));
|
|
75
|
+
if (themeChange) {
|
|
76
|
+
expect(themeChange.instances.length).toBeGreaterThan(0);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
});
|
package/dist/cli.js
CHANGED
|
@@ -1,68 +1,182 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { render } from 'ink';
|
|
3
2
|
import meow from 'meow';
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
3
|
+
import { getOldPackageName, getTargetPackageName, loadConfig } from './config.js';
|
|
4
|
+
import { createSpinner, promptConfirm, promptSelect, renderComplete, renderConfig, renderError, renderHeader, renderNewline, renderScanResults, renderSuccess, renderText, renderWarning } from './render.js';
|
|
5
|
+
import { runCodemods, runScans } from './runner.js';
|
|
6
|
+
import { detectSdk, getSdkVersion, getSupportedSdks, normalizeSdkName } from './util/detect-sdk.js';
|
|
7
|
+
import { detectPackageManager, getPackageManagerDisplayName, removePackage, upgradePackage } from './util/package-manager.js';
|
|
8
|
+
const isInteractive = process.stdin.isTTY;
|
|
7
9
|
const cli = meow(`
|
|
8
10
|
Usage
|
|
9
|
-
$ clerk
|
|
11
|
+
$ npx @clerk/upgrade
|
|
10
12
|
|
|
11
13
|
Options
|
|
12
|
-
--
|
|
13
|
-
--to
|
|
14
|
-
--
|
|
15
|
-
--
|
|
16
|
-
--
|
|
17
|
-
--noWarnings Do not print warnings, only items that must be fixed
|
|
18
|
-
--disableTelemetry Do not send anonymous usage telemetry
|
|
14
|
+
--sdk Name of the SDK you're upgrading (e.g., nextjs, react)
|
|
15
|
+
--dir Directory to scan (defaults to current directory)
|
|
16
|
+
--glob Glob pattern for files to transform (defaults to **/*.{js,jsx,ts,tsx,mjs,cjs})
|
|
17
|
+
--ignore Directories/files to ignore (can be used multiple times)
|
|
18
|
+
--dry-run Show what would be done without making changes
|
|
19
19
|
|
|
20
20
|
Examples
|
|
21
|
-
$ clerk
|
|
22
|
-
$ clerk
|
|
23
|
-
$ clerk
|
|
24
|
-
|
|
21
|
+
$ npx @clerk/upgrade
|
|
22
|
+
$ npx @clerk/upgrade --sdk=nextjs
|
|
23
|
+
$ npx @clerk/upgrade --dir=./src --ignore=**/test/**
|
|
24
|
+
$ npx @clerk/upgrade --dry-run
|
|
25
|
+
|
|
26
|
+
Non-interactive mode:
|
|
27
|
+
When running in CI or piped environments, --sdk is required if it cannot be auto-detected.
|
|
28
|
+
`, {
|
|
25
29
|
importMeta: import.meta,
|
|
26
30
|
flags: {
|
|
27
|
-
|
|
28
|
-
type: 'string'
|
|
29
|
-
},
|
|
30
|
-
to: {
|
|
31
|
+
sdk: {
|
|
31
32
|
type: 'string'
|
|
32
33
|
},
|
|
33
|
-
|
|
34
|
+
dir: {
|
|
34
35
|
type: 'string',
|
|
35
|
-
|
|
36
|
+
default: process.cwd()
|
|
36
37
|
},
|
|
37
|
-
|
|
38
|
-
type: 'string'
|
|
38
|
+
glob: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
default: '**/*.(js|jsx|ts|tsx|mjs|cjs)'
|
|
39
41
|
},
|
|
40
42
|
ignore: {
|
|
41
43
|
type: 'string',
|
|
42
44
|
isMultiple: true
|
|
43
45
|
},
|
|
44
|
-
|
|
45
|
-
type: 'boolean'
|
|
46
|
+
dryRun: {
|
|
47
|
+
type: 'boolean',
|
|
48
|
+
default: false
|
|
46
49
|
},
|
|
47
|
-
|
|
48
|
-
type: 'boolean'
|
|
49
|
-
|
|
50
|
-
disableTelemetry: {
|
|
51
|
-
type: 'boolean'
|
|
50
|
+
skipCodemods: {
|
|
51
|
+
type: 'boolean',
|
|
52
|
+
default: false
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
});
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
56
|
+
async function main() {
|
|
57
|
+
renderHeader();
|
|
58
|
+
const options = {
|
|
59
|
+
dir: cli.flags.dir,
|
|
60
|
+
glob: cli.flags.glob,
|
|
61
|
+
ignore: cli.flags.ignore,
|
|
62
|
+
dryRun: cli.flags.dryRun,
|
|
63
|
+
skipCodemods: cli.flags.skipCodemods
|
|
64
|
+
};
|
|
65
|
+
if (options.dryRun) {
|
|
66
|
+
renderWarning(' Upgrade running in dry run mode - no changes will be made');
|
|
67
|
+
renderNewline();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Step 1: Detect or prompt for SDK
|
|
71
|
+
let sdk = normalizeSdkName(cli.flags.sdk);
|
|
72
|
+
if (!sdk) {
|
|
73
|
+
sdk = detectSdk(options.dir);
|
|
74
|
+
}
|
|
75
|
+
if (!sdk) {
|
|
76
|
+
if (!isInteractive) {
|
|
77
|
+
renderError('Could not detect Clerk SDK. Please provide --sdk flag in non-interactive mode.');
|
|
78
|
+
renderText('Supported SDKs: ' + getSupportedSdks().map(s => s.value).join(', '));
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
const sdkOptions = getSupportedSdks().map(s => ({
|
|
82
|
+
label: s.label,
|
|
83
|
+
value: s.value
|
|
84
|
+
}));
|
|
85
|
+
sdk = await promptSelect('Could not detect Clerk SDK. Please select which SDK you are upgrading:', sdkOptions);
|
|
86
|
+
}
|
|
87
|
+
if (!sdk) {
|
|
88
|
+
renderError('No SDK selected. Exiting.');
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Step 2: Get current version and detect package manager
|
|
93
|
+
const currentVersion = getSdkVersion(sdk, options.dir);
|
|
94
|
+
const packageManager = detectPackageManager(options.dir);
|
|
95
|
+
|
|
96
|
+
// Step 3: Load version config
|
|
97
|
+
const config = await loadConfig(sdk, currentVersion);
|
|
98
|
+
if (!config) {
|
|
99
|
+
renderError(`No upgrade path found for @clerk/${sdk}. Your version may be too old for this upgrade tool.`);
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Step 4: Display configuration
|
|
104
|
+
renderConfig({
|
|
105
|
+
sdk,
|
|
106
|
+
currentVersion,
|
|
107
|
+
fromVersion: config.sdkVersions?.[sdk]?.from,
|
|
108
|
+
toVersion: config.sdkVersions?.[sdk]?.to,
|
|
109
|
+
versionName: config.name,
|
|
110
|
+
dir: options.dir,
|
|
111
|
+
packageManager: getPackageManagerDisplayName(packageManager)
|
|
112
|
+
});
|
|
113
|
+
if (isInteractive && !(await promptConfirm('Ready to upgrade?'))) {
|
|
114
|
+
renderError('Upgrade cancelled. Exiting...');
|
|
115
|
+
process.exit(0);
|
|
116
|
+
}
|
|
117
|
+
console.log('');
|
|
118
|
+
|
|
119
|
+
// Step 5: Handle upgrade status
|
|
120
|
+
if (config.alreadyUpgraded) {
|
|
121
|
+
renderSuccess(`You're already on the latest major version of @clerk/${sdk}`);
|
|
122
|
+
} else if (config.needsUpgrade) {
|
|
123
|
+
await performUpgrade(sdk, packageManager, config, options);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Step 6: Run codemods
|
|
127
|
+
if (config.codemods?.length > 0) {
|
|
128
|
+
renderText(`Running ${config.codemods.length} codemod(s)...`, 'blue');
|
|
129
|
+
await runCodemods(config, sdk, options);
|
|
130
|
+
renderSuccess('All codemods applied');
|
|
131
|
+
renderNewline();
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Step 7: Run scans
|
|
135
|
+
if (config.changes?.length > 0) {
|
|
136
|
+
renderText('Scanning for additional breaking changes...', 'blue');
|
|
137
|
+
const results = await runScans(config, sdk, options);
|
|
138
|
+
renderScanResults(results, config.docsUrl);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Step 8: Done
|
|
142
|
+
renderComplete(sdk, config.docsUrl);
|
|
143
|
+
}
|
|
144
|
+
async function performUpgrade(sdk, packageManager, config, options) {
|
|
145
|
+
const targetPackage = getTargetPackageName(sdk);
|
|
146
|
+
const oldPackage = getOldPackageName(sdk);
|
|
147
|
+
const targetVersion = config.sdkVersions?.[sdk]?.to;
|
|
148
|
+
if (options.dryRun) {
|
|
149
|
+
renderText(`[dry run] Would upgrade ${targetPackage} to version ${targetVersion}`, 'yellow');
|
|
150
|
+
if (oldPackage) {
|
|
151
|
+
renderText(`[dry run] Would remove old package ${oldPackage}`, 'yellow');
|
|
152
|
+
}
|
|
153
|
+
renderNewline();
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Remove old package if this is a rename (clerk-react -> react, clerk-expo -> expo)
|
|
158
|
+
if (oldPackage) {
|
|
159
|
+
const removeSpinner = createSpinner(`Removing ${oldPackage}...`);
|
|
160
|
+
try {
|
|
161
|
+
await removePackage(packageManager, oldPackage, options.dir);
|
|
162
|
+
removeSpinner.success(`Removed ${oldPackage}`);
|
|
163
|
+
} catch {
|
|
164
|
+
removeSpinner.error(`Failed to remove ${oldPackage}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Upgrade to the new version
|
|
169
|
+
const spinner = createSpinner(`Upgrading ${targetPackage} to version ${targetVersion}...`);
|
|
170
|
+
try {
|
|
171
|
+
await upgradePackage(packageManager, targetPackage, targetVersion, options.dir);
|
|
172
|
+
spinner.success(`Upgraded ${targetPackage} to version ${targetVersion}`);
|
|
173
|
+
} catch (error) {
|
|
174
|
+
spinner.error(`Failed to upgrade ${targetPackage}`);
|
|
175
|
+
renderError(error.message);
|
|
176
|
+
process.exit(1);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
main().catch(error => {
|
|
180
|
+
renderError(error.message);
|
|
181
|
+
process.exit(1);
|
|
182
|
+
});
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export const fixtures = [{
|
|
2
|
+
name: 'Renames unstable hooks and handlers to internal',
|
|
3
|
+
source: `
|
|
4
|
+
const clerk = useClerk();
|
|
5
|
+
clerk.__unstable__updateProps({});
|
|
6
|
+
window.__unstable__onAfterSetActive = () => {};
|
|
7
|
+
const opts = { __unstable_invokeMiddlewareOnAuthStateChange: true };
|
|
8
|
+
const handler = client['__unstable__onAfterResponse'];
|
|
9
|
+
`,
|
|
10
|
+
output: `
|
|
11
|
+
const clerk = useClerk();
|
|
12
|
+
clerk.__internal_updateProps({});
|
|
13
|
+
window.__internal_onAfterSetActive = () => {};
|
|
14
|
+
const opts = { __internal_invokeMiddlewareOnAuthStateChange: true };
|
|
15
|
+
const handler = client["__internal_onAfterResponse"];
|
|
16
|
+
`
|
|
17
|
+
}, {
|
|
18
|
+
name: 'Moves UI theme helpers to experimental path and renames identifiers',
|
|
19
|
+
source: `
|
|
20
|
+
import { __experimental_createTheme, experimental__simple, Button } from '@clerk/ui';
|
|
21
|
+
|
|
22
|
+
const theme = __experimental_createTheme();
|
|
23
|
+
const kind = experimental__simple;
|
|
24
|
+
`,
|
|
25
|
+
output: `
|
|
26
|
+
import { Button } from '@clerk/ui';
|
|
27
|
+
|
|
28
|
+
import { createTheme, simple } from "@clerk/ui/themes/experimental";
|
|
29
|
+
|
|
30
|
+
const theme = createTheme();
|
|
31
|
+
const kind = simple;
|
|
32
|
+
`
|
|
33
|
+
}, {
|
|
34
|
+
name: 'Moves UI theme helpers required from root to experimental path',
|
|
35
|
+
source: `
|
|
36
|
+
const { __experimental_createTheme, experimental__simple, Card } = require('@clerk/ui');
|
|
37
|
+
`,
|
|
38
|
+
output: `
|
|
39
|
+
const {
|
|
40
|
+
Card
|
|
41
|
+
} = require('@clerk/ui');
|
|
42
|
+
|
|
43
|
+
const {
|
|
44
|
+
createTheme,
|
|
45
|
+
simple
|
|
46
|
+
} = require("@clerk/ui/themes/experimental");
|
|
47
|
+
`
|
|
48
|
+
}, {
|
|
49
|
+
name: 'Moves chrome extension client creation to background path',
|
|
50
|
+
source: `
|
|
51
|
+
import { __unstable__createClerkClient } from '@clerk/chrome-extension';
|
|
52
|
+
|
|
53
|
+
__unstable__createClerkClient();
|
|
54
|
+
`,
|
|
55
|
+
output: `
|
|
56
|
+
import { createClerkClient } from "@clerk/chrome-extension/background";
|
|
57
|
+
|
|
58
|
+
createClerkClient();
|
|
59
|
+
`
|
|
60
|
+
}, {
|
|
61
|
+
name: 'Removes deprecated billing props from JSX',
|
|
62
|
+
source: `
|
|
63
|
+
<OrganizationProfile __unstable_manageBillingUrl="url" experimental__forceOauthFirst />;
|
|
64
|
+
`,
|
|
65
|
+
output: `
|
|
66
|
+
<OrganizationProfile />;
|
|
67
|
+
`
|
|
68
|
+
}];
|
|
@@ -104,4 +104,17 @@ const clerk = require("@clerk/clerk-react")
|
|
|
104
104
|
output: `
|
|
105
105
|
const clerk = require("@clerk/react")
|
|
106
106
|
`
|
|
107
|
+
}, {
|
|
108
|
+
name: 'Handles directives with mixed legacy imports without double semicolons',
|
|
109
|
+
source: `"use client";
|
|
110
|
+
|
|
111
|
+
import { ClerkProvider, useSignIn, useSignUp } from "@clerk/nextjs";
|
|
112
|
+
|
|
113
|
+
export const dynamic = "force-dynamic";
|
|
114
|
+
`,
|
|
115
|
+
output: `"use client";
|
|
116
|
+
import { ClerkProvider } from "@clerk/nextjs";
|
|
117
|
+
import { useSignIn, useSignUp } from "@clerk/nextjs/legacy";
|
|
118
|
+
|
|
119
|
+
export const dynamic = "force-dynamic";`
|
|
107
120
|
}];
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export const fixtures = [{
|
|
2
|
+
name: 'Renames baseTheme to theme in JSX appearance',
|
|
3
|
+
source: `
|
|
4
|
+
<SignIn appearance={{ baseTheme: dark }} />
|
|
5
|
+
`,
|
|
6
|
+
output: `
|
|
7
|
+
<SignIn appearance={{ theme: dark }} />
|
|
8
|
+
`
|
|
9
|
+
}, {
|
|
10
|
+
name: 'Renames baseTheme and variable keys when appearance object is referenced',
|
|
11
|
+
source: `
|
|
12
|
+
const appearance = {
|
|
13
|
+
baseTheme: [dark, light],
|
|
14
|
+
variables: {
|
|
15
|
+
colorText: '#000',
|
|
16
|
+
colorTextSecondary: '#111',
|
|
17
|
+
colorInputText: '#222',
|
|
18
|
+
colorInputBackground: '#333',
|
|
19
|
+
colorTextOnPrimaryBackground: '#444',
|
|
20
|
+
spacingUnit: '1rem',
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
<SignUp appearance={appearance} />
|
|
25
|
+
`,
|
|
26
|
+
output: `
|
|
27
|
+
const appearance = {
|
|
28
|
+
theme: [dark, light],
|
|
29
|
+
variables: {
|
|
30
|
+
colorForeground: '#000',
|
|
31
|
+
colorMutedForeground: '#111',
|
|
32
|
+
colorInputForeground: '#222',
|
|
33
|
+
colorInput: '#333',
|
|
34
|
+
colorPrimaryForeground: '#444',
|
|
35
|
+
spacing: '1rem',
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
<SignUp appearance={appearance} />
|
|
40
|
+
`
|
|
41
|
+
}, {
|
|
42
|
+
name: 'Handles string literal keys',
|
|
43
|
+
source: `
|
|
44
|
+
const appearance = {
|
|
45
|
+
'baseTheme': dark,
|
|
46
|
+
variables: {
|
|
47
|
+
'colorText': '#000',
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
<SignIn appearance={appearance} />
|
|
52
|
+
`,
|
|
53
|
+
output: `
|
|
54
|
+
const appearance = {
|
|
55
|
+
"theme": dark,
|
|
56
|
+
variables: {
|
|
57
|
+
"colorForeground": '#000',
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
<SignIn appearance={appearance} />
|
|
62
|
+
`
|
|
63
|
+
}];
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export const fixtures = [{
|
|
2
|
+
name: 'Renames root import',
|
|
3
|
+
source: `
|
|
4
|
+
import { dark, light } from '@clerk/themes';
|
|
5
|
+
`,
|
|
6
|
+
output: `
|
|
7
|
+
import { dark, light } from "@clerk/ui/themes";
|
|
8
|
+
`
|
|
9
|
+
}, {
|
|
10
|
+
name: 'Renames subpath import',
|
|
11
|
+
source: `
|
|
12
|
+
import palette from '@clerk/themes/palette';
|
|
13
|
+
`,
|
|
14
|
+
output: `
|
|
15
|
+
import palette from "@clerk/ui/themes/palette";
|
|
16
|
+
`
|
|
17
|
+
}, {
|
|
18
|
+
name: 'Renames require call',
|
|
19
|
+
source: `
|
|
20
|
+
const themes = require('@clerk/themes');
|
|
21
|
+
`,
|
|
22
|
+
output: `
|
|
23
|
+
const themes = require("@clerk/ui/themes");
|
|
24
|
+
`
|
|
25
|
+
}, {
|
|
26
|
+
name: 'Renames dynamic import',
|
|
27
|
+
source: `
|
|
28
|
+
const mod = await import('@clerk/themes/foo');
|
|
29
|
+
`,
|
|
30
|
+
output: `
|
|
31
|
+
const mod = await import("@clerk/ui/themes/foo");
|
|
32
|
+
`
|
|
33
|
+
}, {
|
|
34
|
+
name: 'Renames export source',
|
|
35
|
+
source: `
|
|
36
|
+
export * from '@clerk/themes';
|
|
37
|
+
`,
|
|
38
|
+
output: `
|
|
39
|
+
export * from "@clerk/ui/themes";
|
|
40
|
+
`
|
|
41
|
+
}];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { applyTransform } from 'jscodeshift/dist/testUtils';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import transformer from '../transform-align-experimental-unstable-prefixes.cjs';
|
|
4
|
+
import { fixtures } from './__fixtures__/transform-align-experimental-unstable-prefixes.fixtures';
|
|
5
|
+
describe('transform-align-experimental-unstable-prefixes', () => {
|
|
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
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { applyTransform } from 'jscodeshift/dist/testUtils';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import transformer from '../transform-appearance-layout-to-options.cjs';
|
|
4
|
+
import { fixtures } from './__fixtures__/transform-appearance-layout-to-options.fixtures';
|
|
5
|
+
describe('transform-appearance-layout-to-options', () => {
|
|
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
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { applyTransform } from 'jscodeshift/dist/testUtils';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import transformer from '../transform-remove-deprecated-appearance-props.cjs';
|
|
4
|
+
import { fixtures } from './__fixtures__/transform-remove-deprecated-appearance-props.fixtures';
|
|
5
|
+
describe('transform-remove-deprecated-appearance-props', () => {
|
|
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
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { applyTransform } from 'jscodeshift/dist/testUtils';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import transformer from '../transform-themes-to-ui-themes.cjs';
|
|
4
|
+
import { fixtures } from './__fixtures__/transform-themes-to-ui-themes.fixtures';
|
|
5
|
+
describe('transform-themes-to-ui-themes', () => {
|
|
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
|
@@ -1,32 +1,86 @@
|
|
|
1
1
|
import { dirname, resolve } from 'node:path';
|
|
2
2
|
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import chalk from 'chalk';
|
|
3
4
|
import { globby } from 'globby';
|
|
4
5
|
import { run } from 'jscodeshift/src/Runner.js';
|
|
5
6
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const CODEMOD_CONFIG = {
|
|
8
|
+
'transform-remove-deprecated-props': {
|
|
9
|
+
renderSummary: renderDeprecatedPropsSummary
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
const GLOBBY_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)+', '**/*.(mp4|mkv|wmv|m4v|mov|avi|flv|webm|flac|mka|m4a|aac|ogg)+', '**/*.(css|scss|sass|less|styl)+'];
|
|
6
13
|
export async function runCodemod(transform = 'transform-async-request', glob, options = {}) {
|
|
7
14
|
if (!transform) {
|
|
8
15
|
throw new Error('No transform provided');
|
|
9
16
|
}
|
|
10
17
|
const resolvedPath = resolve(__dirname, `${transform}.cjs`);
|
|
11
18
|
const paths = await globby(glob, {
|
|
12
|
-
ignore:
|
|
13
|
-
// common image files
|
|
14
|
-
'**/*.(mp4|mkv|wmv|m4v|mov|avi|flv|webm|flac|mka|m4a|aac|ogg)+',
|
|
15
|
-
// common video files] }).then(files => {
|
|
16
|
-
'**/*.(css|scss|sass|less|styl)+' // common style files
|
|
17
|
-
]
|
|
19
|
+
ignore: GLOBBY_IGNORE
|
|
18
20
|
});
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
if (options.skipCodemods) {
|
|
22
|
+
return {
|
|
23
|
+
stats: {
|
|
24
|
+
total: 0,
|
|
25
|
+
modified: 0,
|
|
26
|
+
deleted: 0
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// First pass: dry run to collect stats (jscodeshift only reports stats in dry mode)
|
|
32
|
+
const dryResult = await run(resolvedPath, paths ?? [], {
|
|
22
33
|
...options,
|
|
23
|
-
|
|
24
|
-
clerkUpgradeStats,
|
|
25
|
-
// we must silence stdout to prevent output from interfering with ink CLI
|
|
34
|
+
dry: true,
|
|
26
35
|
silent: true
|
|
27
36
|
});
|
|
37
|
+
let result = {};
|
|
38
|
+
if (!options.dryRun) {
|
|
39
|
+
// Second pass: apply the changes
|
|
40
|
+
result = await run(resolvedPath, paths ?? [], {
|
|
41
|
+
...options,
|
|
42
|
+
dry: false,
|
|
43
|
+
silent: true
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
if (options.dry) {
|
|
47
|
+
return dryResult;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Merge stats from dry run into final result
|
|
28
51
|
return {
|
|
29
52
|
...result,
|
|
30
|
-
|
|
53
|
+
stats: dryResult.stats
|
|
31
54
|
};
|
|
55
|
+
}
|
|
56
|
+
export function getCodemodConfig(transform) {
|
|
57
|
+
return CODEMOD_CONFIG[transform] || null;
|
|
58
|
+
}
|
|
59
|
+
function renderDeprecatedPropsSummary(stats) {
|
|
60
|
+
if (!stats) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const userButtonCount = stats.userbuttonAfterSignOutPropsRemoved || 0;
|
|
64
|
+
const hideSlugCount = stats.hideSlugRemoved || 0;
|
|
65
|
+
const beforeEmitCount = stats.beforeEmitTransformed || 0;
|
|
66
|
+
if (!userButtonCount && !hideSlugCount && !beforeEmitCount) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
console.log(chalk.yellow.bold('Manual intervention may be required:'));
|
|
70
|
+
if (userButtonCount > 0) {
|
|
71
|
+
console.log(chalk.yellow(`• Removed ${userButtonCount} UserButton sign-out redirect prop(s)`));
|
|
72
|
+
console.log(chalk.gray(' To configure sign-out redirects:'));
|
|
73
|
+
console.log(chalk.gray(' - Global: Add afterSignOutUrl to <ClerkProvider>'));
|
|
74
|
+
console.log(chalk.gray(' - Per-button: Use <SignOutButton redirectUrl="...">'));
|
|
75
|
+
console.log(chalk.gray(' - Programmatic: clerk.signOut({ redirectUrl: "..." })'));
|
|
76
|
+
}
|
|
77
|
+
if (hideSlugCount > 0) {
|
|
78
|
+
console.log(chalk.yellow(`• Removed ${hideSlugCount} hideSlug prop(s)`));
|
|
79
|
+
console.log(chalk.gray(' Slugs are now managed in the Clerk Dashboard.'));
|
|
80
|
+
}
|
|
81
|
+
if (beforeEmitCount > 0) {
|
|
82
|
+
console.log(chalk.yellow(`• Transformed ${beforeEmitCount} setActive({ beforeEmit }) → setActive({ navigate })`));
|
|
83
|
+
console.log(chalk.gray(' The callback now receives an object with session property.'));
|
|
84
|
+
}
|
|
85
|
+
console.log('');
|
|
32
86
|
}
|