@akinon/projectzero 2.0.0-beta.9 → 2.0.1
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/CHANGELOG.md +191 -17
- package/app-template/.env.example +3 -0
- package/app-template/.github/instructions/account.instructions.md +749 -0
- package/app-template/.github/instructions/checkout.instructions.md +678 -0
- package/app-template/.github/instructions/default.instructions.md +279 -0
- package/app-template/.github/instructions/edge-cases.instructions.md +73 -0
- package/app-template/.github/instructions/routing.instructions.md +603 -0
- package/app-template/.github/instructions/settings.instructions.md +338 -0
- package/app-template/.gitignore +3 -0
- package/app-template/AGENTS.md +7 -0
- package/app-template/CHANGELOG.md +2065 -232
- package/app-template/Procfile +1 -1
- package/app-template/akinon.json +1 -4
- package/app-template/build.sh +10 -0
- package/app-template/docs/advanced-usage.md +111 -0
- package/app-template/docs/plugins.md +60 -25
- package/app-template/docs/sentry-usage.md +35 -0
- package/app-template/jest.config.ts +2 -2
- package/app-template/next-env.d.ts +1 -0
- package/app-template/{next.config.ts → next.config.mjs} +6 -7
- package/app-template/package.json +58 -50
- package/app-template/postcss.config.mjs +1 -4
- package/app-template/public/amex.svg +12 -0
- package/app-template/public/apple-pay.svg +16 -0
- package/app-template/public/assets/images/product-placeholder-1.jpg +0 -0
- package/app-template/public/assets/images/product-placeholder-2.jpg +0 -0
- package/app-template/public/assets/images/product-placeholder-3.jpg +0 -0
- package/app-template/public/assets/images/product-placeholder-4.jpg +0 -0
- package/app-template/public/google-pay.svg +16 -0
- package/app-template/public/locales/en/account.json +9 -4
- package/app-template/public/locales/en/auth.json +6 -7
- package/app-template/public/locales/en/basket.json +6 -6
- package/app-template/public/locales/en/blog.json +7 -0
- package/app-template/public/locales/en/category.json +3 -1
- package/app-template/public/locales/en/checkout.json +17 -4
- package/app-template/public/locales/en/common.json +61 -3
- package/app-template/public/locales/en/forgot_password.json +6 -7
- package/app-template/public/locales/en/product.json +84 -4
- package/app-template/public/locales/tr/account.json +9 -4
- package/app-template/public/locales/tr/auth.json +16 -17
- package/app-template/public/locales/tr/basket.json +4 -4
- package/app-template/public/locales/tr/blog.json +7 -0
- package/app-template/public/locales/tr/category.json +3 -1
- package/app-template/public/locales/tr/checkout.json +48 -36
- package/app-template/public/locales/tr/common.json +60 -2
- package/app-template/public/locales/tr/forgot_password.json +12 -13
- package/app-template/public/locales/tr/product.json +82 -0
- package/app-template/public/logo.svg +3 -27
- package/app-template/public/mastercard.svg +14 -0
- package/app-template/public/masterpass-javascript-sdk-web.min.js +1 -0
- package/app-template/public/promotion-banner.jpg +0 -0
- package/app-template/public/shop-pay.svg +12 -0
- package/app-template/public/visa.svg +12 -0
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/[...prettyurl]/page.tsx +11 -11
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/layout.tsx +4 -3
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/[id]/cancellation/page.tsx +13 -10
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/[id]/page.tsx +73 -51
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/page.tsx +1 -1
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/profile/page.tsx +2 -2
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/address/stores/page.tsx +2 -2
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/auth/page.tsx +1 -1
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/basket/page.tsx +2 -2
- package/app-template/src/app/[pz]/blog/[slug]/page.tsx +120 -0
- package/app-template/src/app/[pz]/category/[pk]/page.tsx +37 -0
- package/app-template/src/app/[pz]/flat-page/[pk]/page.tsx +23 -0
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/forms/[pk]/generate/page.tsx +2 -3
- package/app-template/src/app/[pz]/group-product/[pk]/page.tsx +93 -0
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/landing-page/[pk]/page.tsx +2 -4
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/layout.tsx +6 -11
- package/app-template/src/app/[pz]/list/page.tsx +26 -0
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/not-found.tsx +5 -7
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/orders/completed/[token]/page.tsx +6 -4
- package/app-template/src/app/[pz]/page.tsx +28 -0
- package/app-template/src/app/[pz]/pages/[slug]/page.tsx +19 -0
- package/app-template/src/app/[pz]/product/[pk]/page.tsx +102 -0
- package/app-template/src/app/[pz]/special-page/[pk]/page.tsx +35 -0
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/email-set-primary/[[...id]]/page.tsx +3 -4
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/registration/account-confirm-email/[[...id]]/page.tsx +3 -3
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/reset/[[...id]]/page.tsx +41 -5
- package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/xml-sitemap/[node]/route.ts +8 -6
- package/app-template/src/app/api/auth/[...nextauth]/route.ts +3 -0
- package/app-template/src/app/api/barcode-search/route.ts +1 -0
- package/app-template/src/app/api/cache/route.ts +1 -1
- package/app-template/src/app/api/form/[...id]/route.ts +1 -7
- package/app-template/src/app/api/image-proxy/route.ts +1 -0
- package/app-template/src/app/api/logout/route.ts +1 -1
- package/app-template/src/app/api/product-categories/route.ts +1 -0
- package/app-template/src/app/api/similar-product-list/route.ts +1 -0
- package/app-template/src/app/api/similar-products/route.ts +1 -0
- package/app-template/src/app/api/theme-settings/route.ts +12 -0
- package/app-template/src/app/api/virtual-try-on/limited-categories/route.ts +1 -0
- package/app-template/src/app/api/virtual-try-on/route.ts +1 -0
- package/app-template/src/app/api/web-vitals/route.ts +1 -1
- package/app-template/src/assets/fonts/pz-icon.css +211 -49
- package/app-template/src/assets/fonts/pz-icon.eot +0 -0
- package/app-template/src/assets/fonts/pz-icon.html +486 -0
- package/app-template/src/assets/fonts/pz-icon.scss +373 -49
- package/app-template/src/assets/fonts/pz-icon.svg +215 -53
- package/app-template/src/assets/fonts/pz-icon.ttf +0 -0
- package/app-template/src/assets/fonts/pz-icon.woff +0 -0
- package/app-template/src/assets/fonts/pz-icon.woff2 +0 -0
- package/app-template/src/assets/globals.scss +8 -133
- package/app-template/src/assets/icons/arrow-right.svg +3 -0
- package/app-template/src/assets/icons/cart.svg +4 -12
- package/app-template/src/assets/icons/check.svg +2 -18
- package/app-template/src/assets/icons/chevron-down.svg +2 -7
- package/app-template/src/assets/icons/delete.svg +3 -0
- package/app-template/src/assets/icons/facebook.svg +2 -8
- package/app-template/src/assets/icons/fav-off.svg +5 -0
- package/app-template/src/assets/icons/fav-on.svg +5 -0
- package/app-template/src/assets/icons/filter-and-sort.svg +3 -0
- package/app-template/src/assets/icons/heart.svg +3 -0
- package/app-template/src/assets/icons/instagram.svg +2 -13
- package/app-template/src/assets/icons/materials.svg +3 -0
- package/app-template/src/assets/icons/person.svg +4 -0
- package/app-template/src/assets/icons/pinterest.svg +5 -11
- package/app-template/src/assets/icons/ruler.svg +3 -0
- package/app-template/src/assets/icons/search.svg +8 -11
- package/app-template/src/assets/icons/share.svg +2 -9
- package/app-template/src/assets/icons/snapchat.svg +3 -0
- package/app-template/src/assets/icons/tiktok.svg +3 -0
- package/app-template/src/assets/icons/tumblr.svg +6 -0
- package/app-template/src/assets/icons/twitter.svg +2 -10
- package/app-template/src/assets/icons/vimeo.svg +3 -0
- package/app-template/src/assets/icons/youtube.svg +3 -0
- package/app-template/src/assets/icons/zoom.svg +8 -0
- package/app-template/src/auth.ts +3 -0
- package/app-template/src/components/__tests__/badge.test.tsx +2 -2
- package/app-template/src/components/__tests__/link.test.tsx +2 -0
- package/app-template/src/components/accordion.tsx +48 -23
- package/app-template/src/components/action-tooltip.tsx +160 -0
- package/app-template/src/components/button.tsx +1 -1
- package/app-template/src/components/carousel-core.tsx +4 -11
- package/app-template/src/components/checkbox.tsx +2 -1
- package/app-template/src/components/currency-select.tsx +150 -4
- package/app-template/src/components/file-input.tsx +27 -7
- package/app-template/src/components/generate-form-fields.tsx +49 -10
- package/app-template/src/components/icon.tsx +5 -6
- package/app-template/src/components/index.ts +4 -1
- package/app-template/src/components/input.tsx +11 -5
- package/app-template/src/components/language-select.tsx +88 -2
- package/app-template/src/components/modal.tsx +34 -16
- package/app-template/src/components/pagination.tsx +133 -20
- package/app-template/src/components/price.tsx +1 -1
- package/app-template/src/components/pwa-tags.tsx +1 -0
- package/app-template/src/components/quantity-input.tsx +63 -0
- package/app-template/src/components/quantity-selector.tsx +215 -0
- package/app-template/src/components/route-handler.tsx +50 -0
- package/app-template/src/components/select.tsx +86 -54
- package/app-template/src/components/shimmer.tsx +1 -1
- package/app-template/src/components/types/index.ts +51 -1
- package/app-template/src/components/widget-content.tsx +323 -0
- package/app-template/src/data/server/theme.ts +70 -0
- package/app-template/src/hooks/use-fav-button.tsx +9 -10
- package/app-template/src/hooks/use-product-cart.ts +80 -0
- package/app-template/src/hooks/use-stock-alert.ts +74 -0
- package/app-template/src/hooks/use-theme-settings.ts +42 -0
- package/app-template/src/lib/fonts.ts +149 -0
- package/app-template/src/plugins.js +12 -2
- package/app-template/src/{middleware.ts → proxy.ts} +3 -3
- package/app-template/src/redux/middlewares/category.ts +5 -4
- package/app-template/src/redux/store.ts +21 -1
- package/app-template/src/routes/index.ts +8 -7
- package/app-template/src/settings.js +6 -3
- package/app-template/src/types/hookform-resolvers-yup.d.ts +28 -0
- package/app-template/src/types/index.ts +74 -3
- package/app-template/src/types/next-auth.d.ts +2 -2
- package/app-template/src/types/widget.ts +169 -0
- package/app-template/src/utils/__tests__/theme-page-context.test.ts +145 -0
- package/app-template/src/utils/formatDate.ts +48 -0
- package/app-template/src/utils/styles.ts +71 -0
- package/app-template/src/utils/theme-page-context.ts +309 -0
- package/app-template/src/utils/variant-validation.ts +41 -0
- package/app-template/src/views/account/address-form.tsx +8 -4
- package/app-template/src/views/account/contact-form.tsx +148 -131
- package/app-template/src/views/account/content-header.tsx +4 -3
- package/app-template/src/views/account/faq/faq-tabs.tsx +8 -2
- package/app-template/src/views/account/favorite-item.tsx +1 -1
- package/app-template/src/views/account/order.tsx +11 -9
- package/app-template/src/views/account/orders/order-cancellation-item.tsx +1 -1
- package/app-template/src/views/account/orders/order-detail-header.tsx +1 -1
- package/app-template/src/views/anonymous-tracking/order-detail/index.tsx +45 -38
- package/app-template/src/views/basket/basket-item.tsx +6 -1
- package/app-template/src/views/basket/summary.tsx +16 -0
- package/app-template/src/views/breadcrumb.tsx +2 -2
- package/app-template/src/views/category/category-banner.tsx +4 -23
- package/app-template/src/views/category/category-info.tsx +2 -1
- package/app-template/src/views/category/filters/filter-item.tsx +138 -42
- package/app-template/src/views/category/filters/index.tsx +1 -1
- package/app-template/src/views/category/layout.tsx +1 -0
- package/app-template/src/views/checkout/auth.tsx +64 -40
- package/app-template/src/views/checkout/layout/header.tsx +10 -6
- package/app-template/src/views/checkout/steps/payment/options/credit-card/index.tsx +22 -6
- package/app-template/src/views/checkout/steps/payment/options/funds-transfer.tsx +25 -5
- package/app-template/src/views/checkout/steps/payment/options/loyalty.tsx +21 -2
- package/app-template/src/views/checkout/steps/payment/options/redirection.tsx +27 -5
- package/app-template/src/views/checkout/steps/payment/options/store-credit.tsx +464 -0
- package/app-template/src/views/checkout/steps/payment/payment-option-buttons.tsx +4 -4
- package/app-template/src/views/checkout/steps/shipping/address-box.tsx +33 -20
- package/app-template/src/views/checkout/steps/shipping/addresses.tsx +2 -2
- package/app-template/src/views/checkout/summary.tsx +12 -2
- package/app-template/src/views/find-in-store/index.tsx +2 -2
- package/app-template/src/views/guest-login/index.tsx +62 -58
- package/app-template/src/views/header/action-menu.tsx +1 -1
- package/app-template/src/views/header/band.tsx +2 -2
- package/app-template/src/views/header/index.tsx +1 -1
- package/app-template/src/views/header/mini-basket.tsx +3 -3
- package/app-template/src/views/header/mobile-hamburger-button.tsx +5 -8
- package/app-template/src/views/header/mobile-menu.tsx +18 -6
- package/app-template/src/views/header/navbar.tsx +1 -1
- package/app-template/src/views/header/pwa-back-button.tsx +1 -1
- package/app-template/src/views/header/search/index.tsx +13 -3
- package/app-template/src/views/header/search/results.tsx +1 -1
- package/app-template/src/views/header/user-menu.tsx +1 -3
- package/app-template/src/views/login/index.tsx +66 -57
- package/app-template/src/views/otp-login/index.tsx +11 -6
- package/app-template/src/views/product/index.ts +1 -0
- package/app-template/src/views/product/layout.tsx +26 -6
- package/app-template/src/views/product/price-wrapper.tsx +3 -24
- package/app-template/src/views/product/product-actions.tsx +165 -0
- package/app-template/src/views/product/product-info.tsx +76 -238
- package/app-template/src/views/product/product-share.tsx +58 -0
- package/app-template/src/views/product/product-variants.tsx +26 -0
- package/app-template/src/views/product/slider.tsx +22 -1
- package/app-template/src/views/product/variant.tsx +69 -41
- package/app-template/src/views/product-pointer-banner-item.tsx +1 -1
- package/app-template/src/views/register/index.tsx +31 -46
- package/app-template/src/views/sales-contract-modal/index.tsx +17 -17
- package/app-template/src/views/share/index.tsx +9 -6
- package/app-template/src/views/widgets/home-hero-slider-content.tsx +41 -39
- package/app-template/src/widgets/flatpages/about-us/index.tsx +78 -0
- package/app-template/src/widgets/flatpages/blog-list/index.tsx +129 -0
- package/app-template/src/widgets/footer-info.tsx +1 -1
- package/app-template/src/widgets/footer-menu.tsx +7 -3
- package/app-template/src/widgets/footer-subscription/footer-subscription-form.tsx +17 -14
- package/app-template/src/widgets/footer-subscription/index.tsx +1 -1
- package/app-template/src/widgets/home-stories-eng.tsx +43 -35
- package/app-template/src/widgets/index.ts +7 -0
- package/app-template/src/widgets/schemas/about-us.json +46 -0
- package/app-template/src/widgets/schemas/blog-list.json +37 -0
- package/app-template/src/widgets/schemas/blog.json +29 -0
- package/app-template/tailwind.config.js +155 -7
- package/app-template/tsconfig.json +29 -11
- package/codemods/migrate-auth-v5/index.js +339 -0
- package/codemods/migrate-auth-v5/transform.js +86 -0
- package/codemods/migrate-segments/index.js +591 -0
- package/codemods/update-tailwind-config/index.js +30 -0
- package/codemods/update-tailwind-config/transform.js +102 -0
- package/codemods/upgrade-to-2/index.js +549 -0
- package/commands/codemod.ts +0 -1
- package/commands/plugins.ts +111 -46
- package/dist/commands/codemod.js +0 -1
- package/dist/commands/plugins.js +104 -36
- package/package.json +3 -2
- package/app-template/src/app/[commerce]/[locale]/[currency]/category/[pk]/page.tsx +0 -22
- package/app-template/src/app/[commerce]/[locale]/[currency]/flat-page/[pk]/page.tsx +0 -20
- package/app-template/src/app/[commerce]/[locale]/[currency]/group-product/[pk]/page.tsx +0 -74
- package/app-template/src/app/[commerce]/[locale]/[currency]/list/page.tsx +0 -18
- package/app-template/src/app/[commerce]/[locale]/[currency]/page.tsx +0 -50
- package/app-template/src/app/[commerce]/[locale]/[currency]/product/[pk]/page.tsx +0 -84
- package/app-template/src/app/[commerce]/[locale]/[currency]/special-page/[pk]/page.tsx +0 -27
- package/app-template/src/pages/api/auth/[...nextauth].ts +0 -3
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/address/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/change-email/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/change-password/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/contact/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/coupons/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/email-verification/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/faq/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/favourite-products/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/my-quotations/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/[id]/layout.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/account/orders/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/anonymous-tracking/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/auth/oauth-login/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/basket-b2b/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/category/[pk]/loading.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/client-root.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/contact-us/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/error.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/flat-page/[pk]/loading.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/group-product/[pk]/loading.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/landing-page/[pk]/loading.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/list/loading.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/orders/checkout/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/orders/completed/[token]/layout.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/special-page/[pk]/loading.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/template.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/users/password/reset/page.tsx +0 -0
- /package/app-template/src/app/{[commerce]/[locale]/[currency] → [pz]}/xml-sitemap/route.ts +0 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
function transform(fileInfo, api) {
|
|
2
|
+
const j = api.jscodeshift;
|
|
3
|
+
const root = j(fileInfo.source);
|
|
4
|
+
|
|
5
|
+
if (!fileInfo.path.includes('tailwind.config.js')) {
|
|
6
|
+
return fileInfo.source;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
console.log(`Processing file: ${fileInfo.path}`);
|
|
10
|
+
|
|
11
|
+
const hasAkinonNextImport = root.find(j.VariableDeclarator, {
|
|
12
|
+
id: { name: 'getAkinonNextContent' }
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
if (hasAkinonNextImport.size() === 0) {
|
|
16
|
+
const requireStatement = j.variableDeclaration('const', [
|
|
17
|
+
j.variableDeclarator(
|
|
18
|
+
j.identifier('getAkinonNextContent'),
|
|
19
|
+
j.callExpression(j.identifier('require'), [
|
|
20
|
+
j.literal('@akinon/next/tailwind/content')
|
|
21
|
+
])
|
|
22
|
+
)
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
root.get().node.program.body.unshift(requireStatement);
|
|
26
|
+
|
|
27
|
+
console.log(`Added getAkinonNextContent import to ${fileInfo.path}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const defaultConfig = root
|
|
31
|
+
.find(j.VariableDeclarator, {
|
|
32
|
+
id: { name: 'defaultConfig' },
|
|
33
|
+
init: { type: 'ObjectExpression' }
|
|
34
|
+
})
|
|
35
|
+
.paths()[0];
|
|
36
|
+
|
|
37
|
+
if (!defaultConfig) {
|
|
38
|
+
console.log(`No defaultConfig found in ${fileInfo.path}`);
|
|
39
|
+
return fileInfo.source;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const contentArray = defaultConfig.value.init.properties.find(
|
|
43
|
+
(prop) =>
|
|
44
|
+
prop.key.name === 'content' && prop.value.type === 'ArrayExpression'
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
if (!contentArray) {
|
|
48
|
+
console.log(`No content array found in defaultConfig`);
|
|
49
|
+
return fileInfo.source;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const pluginsVarName = root
|
|
53
|
+
.find(j.VariableDeclarator, {
|
|
54
|
+
id: { name: 'plugins' },
|
|
55
|
+
init: {
|
|
56
|
+
type: 'CallExpression',
|
|
57
|
+
callee: { name: 'require' }
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
.paths()[0]?.value.id.name;
|
|
61
|
+
|
|
62
|
+
if (!pluginsVarName) {
|
|
63
|
+
console.log(`No plugins variable found in ${fileInfo.path}`);
|
|
64
|
+
return fileInfo.source;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const contentElements = contentArray.value.elements;
|
|
68
|
+
|
|
69
|
+
const filteredElements = contentElements.filter((element) => {
|
|
70
|
+
if (element.type === 'SpreadElement') {
|
|
71
|
+
if (
|
|
72
|
+
element.argument.type === 'CallExpression' &&
|
|
73
|
+
element.argument.callee.object?.callee.object.name === 'plugins'
|
|
74
|
+
) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (
|
|
79
|
+
element.argument.type === 'CallExpression' &&
|
|
80
|
+
element.argument.callee.name === 'getAkinonNextContent'
|
|
81
|
+
) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return true;
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
filteredElements.push(
|
|
89
|
+
j.spreadElement(
|
|
90
|
+
j.callExpression(j.identifier('getAkinonNextContent'), [
|
|
91
|
+
j.identifier(pluginsVarName)
|
|
92
|
+
])
|
|
93
|
+
)
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
contentArray.value.elements = filteredElements;
|
|
97
|
+
|
|
98
|
+
console.log(`Successfully updated ${fileInfo.path}`);
|
|
99
|
+
return root.toSource();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = transform;
|
|
@@ -0,0 +1,549 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* upgrade-to-2: orchestrator codemod that chains every step required to move
|
|
3
|
+
* a Project Zero brand project from pz-next 1.x to 2.0 beta.
|
|
4
|
+
*
|
|
5
|
+
* Steps (in order):
|
|
6
|
+
* 1. Preflight checks (git state, package.json, Node.js project)
|
|
7
|
+
* 2. Create a backup git branch (pre-upgrade-2-YYYYMMDD)
|
|
8
|
+
* 3. Bump package.json dependencies to the 2.0 target matrix
|
|
9
|
+
* 4. Run @next/codemod upgrade (Next 16 + React 19)
|
|
10
|
+
* 5. Run migrate-auth-v5 codemod (next-auth v4 -> v5)
|
|
11
|
+
* 6. Run sentry-9 codemod (only when @sentry/nextjs is present)
|
|
12
|
+
* 7. yarn clean && yarn install
|
|
13
|
+
* 8. yarn build (validation)
|
|
14
|
+
* 9. Summary report
|
|
15
|
+
*
|
|
16
|
+
* Out of scope in this first version:
|
|
17
|
+
* - Tailwind v3 -> v4 migration (run manually with @tailwindcss/upgrade)
|
|
18
|
+
* - migrate-segments codemod (separate task)
|
|
19
|
+
*
|
|
20
|
+
* Usage:
|
|
21
|
+
* cd <brand-root>
|
|
22
|
+
* npx @akinon/projectzero codemod --codemod=upgrade-to-2 [flags]
|
|
23
|
+
*
|
|
24
|
+
* Flags:
|
|
25
|
+
* --dry-run Preview only. No package.json writes, no install,
|
|
26
|
+
* codemods invoked in dry-run where supported.
|
|
27
|
+
* --skip-preflight Skip git state / package.json checks
|
|
28
|
+
* --skip-backup Do not create pre-upgrade-2-* branch
|
|
29
|
+
* --skip-bump Do not modify package.json
|
|
30
|
+
* --skip-next-codemod Do not run @next/codemod upgrade
|
|
31
|
+
* --skip-auth Do not run migrate-auth-v5
|
|
32
|
+
* --skip-sentry Do not run sentry-9 (auto-skipped if not needed)
|
|
33
|
+
* --skip-install Do not run yarn install
|
|
34
|
+
* --skip-build Do not run yarn build
|
|
35
|
+
* --interactive Pause for confirmation after each step
|
|
36
|
+
* --verbose Extra logs
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
const path = require('path');
|
|
40
|
+
const fs = require('fs');
|
|
41
|
+
const { execSync, spawnSync } = require('child_process');
|
|
42
|
+
const readline = require('readline');
|
|
43
|
+
|
|
44
|
+
const AUTH_CODEMOD = path.resolve(__dirname, '..', 'migrate-auth-v5');
|
|
45
|
+
const SENTRY_CODEMOD = path.resolve(__dirname, '..', 'sentry-9');
|
|
46
|
+
|
|
47
|
+
const TARGET_MATRIX = {
|
|
48
|
+
dependencies: {
|
|
49
|
+
next: '16.2.4',
|
|
50
|
+
react: '19.2.5',
|
|
51
|
+
'react-dom': '19.2.5',
|
|
52
|
+
'next-auth': '5.0.0-beta.25',
|
|
53
|
+
'@akinon/next': 'beta'
|
|
54
|
+
},
|
|
55
|
+
devDependencies: {
|
|
56
|
+
'@types/react': '19.2.14',
|
|
57
|
+
'@types/react-dom': '19.2.3',
|
|
58
|
+
'eslint-config-next': '16.2.4',
|
|
59
|
+
tailwindcss: '3.4.17',
|
|
60
|
+
'@akinon/projectzero': 'beta',
|
|
61
|
+
'@akinon/eslint-plugin-projectzero': 'beta',
|
|
62
|
+
'@akinon/tsconfig': 'beta'
|
|
63
|
+
},
|
|
64
|
+
conditional: {
|
|
65
|
+
'@sentry/nextjs': '^9.0.0'
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const STEP_COLUMN_WIDTH = 32;
|
|
70
|
+
|
|
71
|
+
function log(msg) {
|
|
72
|
+
const ts = new Date().toISOString().replace('T', ' ').slice(0, 19);
|
|
73
|
+
console.log(`[${ts}] ${msg}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function logStep(step, msg) {
|
|
77
|
+
const padded = step.padEnd(STEP_COLUMN_WIDTH, ' ');
|
|
78
|
+
log(`${padded} ${msg}`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function runCommand(cmd, { cwd, dryRun, verbose }) {
|
|
82
|
+
if (dryRun) {
|
|
83
|
+
log(`[DRY] ${cmd}`);
|
|
84
|
+
return { status: 0, dry: true };
|
|
85
|
+
}
|
|
86
|
+
if (verbose) log(`$ ${cmd}`);
|
|
87
|
+
try {
|
|
88
|
+
execSync(cmd, { cwd, stdio: 'inherit' });
|
|
89
|
+
return { status: 0 };
|
|
90
|
+
} catch (err) {
|
|
91
|
+
return { status: err.status || 1, error: err };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function confirm(question) {
|
|
96
|
+
return new Promise((resolve) => {
|
|
97
|
+
const rl = readline.createInterface({
|
|
98
|
+
input: process.stdin,
|
|
99
|
+
output: process.stdout
|
|
100
|
+
});
|
|
101
|
+
rl.question(`${question} [Y/n] `, (answer) => {
|
|
102
|
+
rl.close();
|
|
103
|
+
resolve(answer.trim().toLowerCase() !== 'n');
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function parseArgs(argv) {
|
|
109
|
+
const flags = {
|
|
110
|
+
dryRun: argv.includes('--dry-run'),
|
|
111
|
+
skipPreflight: argv.includes('--skip-preflight'),
|
|
112
|
+
skipBackup: argv.includes('--skip-backup'),
|
|
113
|
+
skipBump: argv.includes('--skip-bump'),
|
|
114
|
+
skipNextCodemod: argv.includes('--skip-next-codemod'),
|
|
115
|
+
skipAuth: argv.includes('--skip-auth'),
|
|
116
|
+
skipSentry: argv.includes('--skip-sentry'),
|
|
117
|
+
skipInstall: argv.includes('--skip-install'),
|
|
118
|
+
skipBuild: argv.includes('--skip-build'),
|
|
119
|
+
interactive: argv.includes('--interactive'),
|
|
120
|
+
verbose: argv.includes('--verbose')
|
|
121
|
+
};
|
|
122
|
+
return flags;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function readPackageJson(cwd) {
|
|
126
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
127
|
+
if (!fs.existsSync(pkgPath)) return null;
|
|
128
|
+
return JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function writePackageJson(cwd, pkg) {
|
|
132
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
133
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function stepPreflight(cwd, flags) {
|
|
137
|
+
logStep('[1/9] Preflight', 'starting');
|
|
138
|
+
|
|
139
|
+
const pkg = readPackageJson(cwd);
|
|
140
|
+
if (!pkg) {
|
|
141
|
+
throw new Error('No package.json found in working directory');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!pkg.dependencies?.next && !pkg.devDependencies?.next) {
|
|
145
|
+
throw new Error('This does not appear to be a Next.js project (no `next` dependency)');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const gitStatus = spawnSync('git', ['status', '--porcelain'], {
|
|
149
|
+
cwd,
|
|
150
|
+
encoding: 'utf-8'
|
|
151
|
+
});
|
|
152
|
+
if (gitStatus.status !== 0) {
|
|
153
|
+
throw new Error('git not available or not a git repo');
|
|
154
|
+
}
|
|
155
|
+
const dirty = gitStatus.stdout.trim().length > 0;
|
|
156
|
+
if (dirty && !flags.dryRun) {
|
|
157
|
+
throw new Error(
|
|
158
|
+
'Working directory has uncommitted changes. Commit or stash before running upgrade-to-2.'
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const currentNext =
|
|
163
|
+
pkg.dependencies?.next || pkg.devDependencies?.next || 'unknown';
|
|
164
|
+
const currentReact = pkg.dependencies?.react || 'unknown';
|
|
165
|
+
const currentAuth = pkg.dependencies?.['next-auth'] || 'unknown';
|
|
166
|
+
const currentAkinon = pkg.dependencies?.['@akinon/next'] || 'unknown';
|
|
167
|
+
|
|
168
|
+
log(` Current: next@${currentNext} react@${currentReact} next-auth@${currentAuth} @akinon/next@${currentAkinon}`);
|
|
169
|
+
log(` Target: next@${TARGET_MATRIX.dependencies.next} react@${TARGET_MATRIX.dependencies.react} next-auth@${TARGET_MATRIX.dependencies['next-auth']} @akinon/next@beta`);
|
|
170
|
+
|
|
171
|
+
logStep('[1/9] Preflight', 'ok');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function stepBackup(cwd, flags) {
|
|
175
|
+
if (flags.skipBackup) {
|
|
176
|
+
logStep('[2/9] Backup branch', 'skipped');
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
const today = new Date().toISOString().slice(0, 10).replace(/-/g, '');
|
|
180
|
+
const branchName = `pre-upgrade-2-${today}`;
|
|
181
|
+
|
|
182
|
+
if (flags.dryRun) {
|
|
183
|
+
logStep('[2/9] Backup branch', `[DRY] git branch ${branchName}`);
|
|
184
|
+
return branchName;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const existing = spawnSync(
|
|
188
|
+
'git',
|
|
189
|
+
['rev-parse', '--verify', branchName],
|
|
190
|
+
{ cwd, encoding: 'utf-8' }
|
|
191
|
+
);
|
|
192
|
+
if (existing.status === 0) {
|
|
193
|
+
logStep('[2/9] Backup branch', `already exists: ${branchName}`);
|
|
194
|
+
return branchName;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const result = spawnSync('git', ['branch', branchName], {
|
|
198
|
+
cwd,
|
|
199
|
+
stdio: 'inherit'
|
|
200
|
+
});
|
|
201
|
+
if (result.status !== 0) {
|
|
202
|
+
throw new Error(`Failed to create backup branch ${branchName}`);
|
|
203
|
+
}
|
|
204
|
+
logStep('[2/9] Backup branch', `created ${branchName}`);
|
|
205
|
+
return branchName;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function bumpDepsSection(section, matrix) {
|
|
209
|
+
const changes = [];
|
|
210
|
+
if (!section) return { section: section || {}, changes };
|
|
211
|
+
for (const [name, version] of Object.entries(matrix)) {
|
|
212
|
+
if (section[name] !== undefined && section[name] !== version) {
|
|
213
|
+
changes.push(`${name}: ${section[name]} -> ${version}`);
|
|
214
|
+
section[name] = version;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return { section, changes };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function pinNextScriptsToWebpack(pkg) {
|
|
221
|
+
// Next 16 defaults build/dev to Turbopack, which surfaces bundle-time
|
|
222
|
+
// errors for Node APIs used on the edge runtime (e.g. CompressionStream
|
|
223
|
+
// inside @akinon/next/lib/cache.ts). pz-next itself ships with
|
|
224
|
+
// `next dev --webpack` / `next build --webpack` until those are fixed;
|
|
225
|
+
// brand projects need the same flag to build successfully.
|
|
226
|
+
const changes = [];
|
|
227
|
+
if (!pkg.scripts) return changes;
|
|
228
|
+
|
|
229
|
+
['dev', 'build'].forEach((scriptName) => {
|
|
230
|
+
const current = pkg.scripts[scriptName];
|
|
231
|
+
if (typeof current !== 'string') return;
|
|
232
|
+
if (current.includes('--webpack')) return;
|
|
233
|
+
if (!/\bnext\s+(dev|build)\b/.test(current)) return;
|
|
234
|
+
const updated = current.replace(
|
|
235
|
+
/\bnext\s+(dev|build)\b/,
|
|
236
|
+
'next $1 --webpack'
|
|
237
|
+
);
|
|
238
|
+
pkg.scripts[scriptName] = updated;
|
|
239
|
+
changes.push(`scripts.${scriptName}: "${current}" -> "${updated}"`);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
return changes;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function stepBump(cwd, flags) {
|
|
246
|
+
if (flags.skipBump) {
|
|
247
|
+
logStep('[3/9] Bump deps', 'skipped');
|
|
248
|
+
return { hasSentry: false, changes: [] };
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const pkg = readPackageJson(cwd);
|
|
252
|
+
const hasSentry = Boolean(pkg.dependencies?.['@sentry/nextjs']);
|
|
253
|
+
|
|
254
|
+
const allChanges = [];
|
|
255
|
+
const deps = bumpDepsSection(pkg.dependencies, TARGET_MATRIX.dependencies);
|
|
256
|
+
allChanges.push(...deps.changes);
|
|
257
|
+
pkg.dependencies = deps.section;
|
|
258
|
+
|
|
259
|
+
const devDeps = bumpDepsSection(
|
|
260
|
+
pkg.devDependencies,
|
|
261
|
+
TARGET_MATRIX.devDependencies
|
|
262
|
+
);
|
|
263
|
+
allChanges.push(...devDeps.changes);
|
|
264
|
+
pkg.devDependencies = devDeps.section;
|
|
265
|
+
|
|
266
|
+
if (hasSentry) {
|
|
267
|
+
const sentryDeps = bumpDepsSection(pkg.dependencies, {
|
|
268
|
+
'@sentry/nextjs': TARGET_MATRIX.conditional['@sentry/nextjs']
|
|
269
|
+
});
|
|
270
|
+
allChanges.push(...sentryDeps.changes);
|
|
271
|
+
pkg.dependencies = sentryDeps.section;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const scriptChanges = pinNextScriptsToWebpack(pkg);
|
|
275
|
+
allChanges.push(...scriptChanges);
|
|
276
|
+
|
|
277
|
+
if (allChanges.length === 0) {
|
|
278
|
+
logStep('[3/9] Bump deps', 'already at target, no changes');
|
|
279
|
+
return { hasSentry, changes: [] };
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (flags.dryRun) {
|
|
283
|
+
logStep('[3/9] Bump deps', `[DRY] ${allChanges.length} changes`);
|
|
284
|
+
allChanges.forEach((c) => log(` - ${c}`));
|
|
285
|
+
} else {
|
|
286
|
+
writePackageJson(cwd, pkg);
|
|
287
|
+
logStep('[3/9] Bump deps', `${allChanges.length} changes applied`);
|
|
288
|
+
if (flags.verbose) allChanges.forEach((c) => log(` - ${c}`));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return { hasSentry, changes: allChanges };
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function stepNextCodemod(cwd, flags) {
|
|
295
|
+
if (flags.skipNextCodemod) {
|
|
296
|
+
logStep('[5/9] Next codemod', 'skipped');
|
|
297
|
+
return { ok: true };
|
|
298
|
+
}
|
|
299
|
+
const cmd = flags.dryRun
|
|
300
|
+
? 'npx --yes @next/codemod@latest upgrade latest --verbose'
|
|
301
|
+
: 'npx --yes @next/codemod@latest upgrade latest';
|
|
302
|
+
logStep('[5/9] Next codemod', `running ${cmd}`);
|
|
303
|
+
const result = runCommand(cmd, { cwd, dryRun: false, verbose: flags.verbose });
|
|
304
|
+
if (result.status !== 0) {
|
|
305
|
+
logStep('[5/9] Next codemod', `FAILED (exit ${result.status})`);
|
|
306
|
+
return { ok: false };
|
|
307
|
+
}
|
|
308
|
+
logStep('[5/9] Next codemod', 'ok');
|
|
309
|
+
return { ok: true };
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function stepAuthCodemod(cwd, flags) {
|
|
313
|
+
if (flags.skipAuth) {
|
|
314
|
+
logStep('[6/9] Auth codemod', 'skipped');
|
|
315
|
+
return { ok: true };
|
|
316
|
+
}
|
|
317
|
+
logStep('[6/9] Auth codemod', 'running migrate-auth-v5');
|
|
318
|
+
try {
|
|
319
|
+
const prevArgv = process.argv;
|
|
320
|
+
process.argv = [
|
|
321
|
+
process.argv[0],
|
|
322
|
+
process.argv[1],
|
|
323
|
+
...(flags.dryRun ? ['--dry-run'] : [])
|
|
324
|
+
];
|
|
325
|
+
const codemod = require(AUTH_CODEMOD);
|
|
326
|
+
const savedCwd = process.cwd();
|
|
327
|
+
process.chdir(cwd);
|
|
328
|
+
const result = codemod.transform();
|
|
329
|
+
const finish = () => {
|
|
330
|
+
process.chdir(savedCwd);
|
|
331
|
+
process.argv = prevArgv;
|
|
332
|
+
};
|
|
333
|
+
if (result && typeof result.then === 'function') {
|
|
334
|
+
return result.then(
|
|
335
|
+
() => {
|
|
336
|
+
finish();
|
|
337
|
+
logStep('[6/9] Auth codemod', 'ok');
|
|
338
|
+
return { ok: true };
|
|
339
|
+
},
|
|
340
|
+
(err) => {
|
|
341
|
+
finish();
|
|
342
|
+
logStep('[6/9] Auth codemod', `FAILED: ${err.message}`);
|
|
343
|
+
return { ok: false };
|
|
344
|
+
}
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
finish();
|
|
348
|
+
logStep('[6/9] Auth codemod', 'ok');
|
|
349
|
+
return { ok: true };
|
|
350
|
+
} catch (err) {
|
|
351
|
+
logStep('[6/9] Auth codemod', `FAILED: ${err.message}`);
|
|
352
|
+
return { ok: false };
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function stepSentryCodemod(cwd, flags, hasSentry) {
|
|
357
|
+
if (flags.skipSentry || !hasSentry) {
|
|
358
|
+
const reason = flags.skipSentry ? 'skipped' : 'no @sentry/nextjs, skipping';
|
|
359
|
+
logStep('[7/9] Sentry codemod', reason);
|
|
360
|
+
return { ok: true };
|
|
361
|
+
}
|
|
362
|
+
if (flags.dryRun) {
|
|
363
|
+
logStep('[7/9] Sentry codemod', '[DRY] would run sentry-9');
|
|
364
|
+
return { ok: true };
|
|
365
|
+
}
|
|
366
|
+
logStep('[7/9] Sentry codemod', 'running sentry-9');
|
|
367
|
+
try {
|
|
368
|
+
const savedCwd = process.cwd();
|
|
369
|
+
process.chdir(cwd);
|
|
370
|
+
const codemod = require(SENTRY_CODEMOD);
|
|
371
|
+
codemod.transform();
|
|
372
|
+
process.chdir(savedCwd);
|
|
373
|
+
logStep('[7/9] Sentry codemod', 'ok');
|
|
374
|
+
return { ok: true };
|
|
375
|
+
} catch (err) {
|
|
376
|
+
logStep('[7/9] Sentry codemod', `FAILED: ${err.message}`);
|
|
377
|
+
return { ok: false };
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function stepInstall(cwd, flags) {
|
|
382
|
+
if (flags.skipInstall) {
|
|
383
|
+
logStep('[4/9] yarn install', 'skipped');
|
|
384
|
+
return { ok: true };
|
|
385
|
+
}
|
|
386
|
+
if (flags.dryRun) {
|
|
387
|
+
logStep('[4/9] yarn install', '[DRY] yarn clean && yarn');
|
|
388
|
+
return { ok: true };
|
|
389
|
+
}
|
|
390
|
+
logStep('[4/9] yarn install', 'running yarn clean && yarn');
|
|
391
|
+
const clean = runCommand('yarn clean', {
|
|
392
|
+
cwd,
|
|
393
|
+
dryRun: false,
|
|
394
|
+
verbose: flags.verbose
|
|
395
|
+
});
|
|
396
|
+
if (clean.status !== 0) {
|
|
397
|
+
log(' yarn clean failed, continuing with yarn install');
|
|
398
|
+
}
|
|
399
|
+
const install = runCommand('yarn', {
|
|
400
|
+
cwd,
|
|
401
|
+
dryRun: false,
|
|
402
|
+
verbose: flags.verbose
|
|
403
|
+
});
|
|
404
|
+
if (install.status !== 0) {
|
|
405
|
+
logStep('[4/9] yarn install', `FAILED (exit ${install.status})`);
|
|
406
|
+
return { ok: false };
|
|
407
|
+
}
|
|
408
|
+
logStep('[4/9] yarn install', 'ok');
|
|
409
|
+
return { ok: true };
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function stepBuild(cwd, flags) {
|
|
413
|
+
if (flags.skipBuild) {
|
|
414
|
+
logStep('[8/9] yarn build', 'skipped');
|
|
415
|
+
return { ok: true };
|
|
416
|
+
}
|
|
417
|
+
if (flags.dryRun) {
|
|
418
|
+
logStep('[8/9] yarn build', '[DRY] yarn build');
|
|
419
|
+
return { ok: true };
|
|
420
|
+
}
|
|
421
|
+
logStep('[8/9] yarn build', 'running');
|
|
422
|
+
const result = runCommand('yarn build', {
|
|
423
|
+
cwd,
|
|
424
|
+
dryRun: false,
|
|
425
|
+
verbose: flags.verbose
|
|
426
|
+
});
|
|
427
|
+
if (result.status !== 0) {
|
|
428
|
+
logStep('[8/9] yarn build', `FAILED (exit ${result.status})`);
|
|
429
|
+
return { ok: false };
|
|
430
|
+
}
|
|
431
|
+
logStep('[8/9] yarn build', 'ok');
|
|
432
|
+
return { ok: true };
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
function countTodoMarkers(cwd) {
|
|
436
|
+
const authFile = path.join(cwd, 'src', 'auth.ts');
|
|
437
|
+
if (!fs.existsSync(authFile)) return 0;
|
|
438
|
+
const content = fs.readFileSync(authFile, 'utf-8');
|
|
439
|
+
return (content.match(/TODO:v5/g) || []).length;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
function stepReport(cwd, results) {
|
|
443
|
+
logStep('[9/9] Report', 'summary');
|
|
444
|
+
const pkg = readPackageJson(cwd) || {};
|
|
445
|
+
const todoCount = countTodoMarkers(cwd);
|
|
446
|
+
|
|
447
|
+
console.log('\n==================== upgrade-to-2 summary ====================');
|
|
448
|
+
console.log(` Preflight: ${results.preflight ? 'ok' : 'failed'}`);
|
|
449
|
+
console.log(` Backup branch: ${results.backupBranch || 'skipped'}`);
|
|
450
|
+
console.log(` Deps changes: ${results.bumpChanges}`);
|
|
451
|
+
console.log(` Install: ${results.install ? 'ok' : 'FAILED'}`);
|
|
452
|
+
console.log(` Next codemod: ${results.nextCodemod ? 'ok' : 'FAILED'}`);
|
|
453
|
+
console.log(` Auth codemod: ${results.authCodemod ? 'ok' : 'FAILED'}`);
|
|
454
|
+
console.log(` Sentry codemod: ${results.sentryCodemod ? 'ok' : results.sentrySkippedReason || 'FAILED'}`);
|
|
455
|
+
console.log(` Build: ${results.build ? 'ok' : 'FAILED'}`);
|
|
456
|
+
console.log('');
|
|
457
|
+
console.log(` Versions after:`);
|
|
458
|
+
console.log(` next: ${pkg.dependencies?.next || '-'}`);
|
|
459
|
+
console.log(` react: ${pkg.dependencies?.react || '-'}`);
|
|
460
|
+
console.log(` next-auth: ${pkg.dependencies?.['next-auth'] || '-'}`);
|
|
461
|
+
console.log(` @akinon/next: ${pkg.dependencies?.['@akinon/next'] || '-'}`);
|
|
462
|
+
if (pkg.dependencies?.['@sentry/nextjs']) {
|
|
463
|
+
console.log(` @sentry/nextjs: ${pkg.dependencies['@sentry/nextjs']}`);
|
|
464
|
+
}
|
|
465
|
+
console.log('');
|
|
466
|
+
if (todoCount > 0) {
|
|
467
|
+
console.log(` Manual work left in src/auth.ts: ${todoCount} TODO:v5 markers`);
|
|
468
|
+
console.log(` grep -n "TODO:v5" src/auth.ts`);
|
|
469
|
+
}
|
|
470
|
+
console.log(' Next steps (manual):');
|
|
471
|
+
console.log(' - Tailwind v4 migration: npx @tailwindcss/upgrade@latest');
|
|
472
|
+
console.log(' - Review backup branch: ' + (results.backupBranch || 'n/a'));
|
|
473
|
+
console.log(' - Run dev server and smoke test auth, cart, checkout');
|
|
474
|
+
console.log('==============================================================\n');
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
async function maybePause(flags, stepLabel) {
|
|
478
|
+
if (!flags.interactive) return true;
|
|
479
|
+
const ok = await confirm(`Continue after ${stepLabel}?`);
|
|
480
|
+
if (!ok) {
|
|
481
|
+
log('Aborted by user.');
|
|
482
|
+
process.exit(1);
|
|
483
|
+
}
|
|
484
|
+
return true;
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
async function transform() {
|
|
488
|
+
const cwd = path.resolve(process.cwd());
|
|
489
|
+
const flags = parseArgs(process.argv);
|
|
490
|
+
|
|
491
|
+
log(`upgrade-to-2 starting in ${cwd}${flags.dryRun ? ' (DRY RUN)' : ''}`);
|
|
492
|
+
|
|
493
|
+
const results = {};
|
|
494
|
+
|
|
495
|
+
try {
|
|
496
|
+
if (!flags.skipPreflight) {
|
|
497
|
+
stepPreflight(cwd, flags);
|
|
498
|
+
results.preflight = true;
|
|
499
|
+
await maybePause(flags, 'preflight');
|
|
500
|
+
} else {
|
|
501
|
+
logStep('[1/9] Preflight', 'skipped');
|
|
502
|
+
results.preflight = true;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
results.backupBranch = stepBackup(cwd, flags);
|
|
506
|
+
await maybePause(flags, 'backup');
|
|
507
|
+
|
|
508
|
+
const bumpResult = stepBump(cwd, flags);
|
|
509
|
+
results.bumpChanges = bumpResult.changes.length;
|
|
510
|
+
const hasSentry = bumpResult.hasSentry;
|
|
511
|
+
await maybePause(flags, 'bump');
|
|
512
|
+
|
|
513
|
+
results.install = stepInstall(cwd, flags).ok;
|
|
514
|
+
await maybePause(flags, 'install');
|
|
515
|
+
|
|
516
|
+
results.nextCodemod = stepNextCodemod(cwd, flags).ok;
|
|
517
|
+
await maybePause(flags, 'next-codemod');
|
|
518
|
+
|
|
519
|
+
const authResult = stepAuthCodemod(cwd, flags);
|
|
520
|
+
const authAwaited = authResult && typeof authResult.then === 'function'
|
|
521
|
+
? await authResult
|
|
522
|
+
: authResult;
|
|
523
|
+
results.authCodemod = authAwaited.ok;
|
|
524
|
+
await maybePause(flags, 'auth-codemod');
|
|
525
|
+
|
|
526
|
+
const sentryResult = stepSentryCodemod(cwd, flags, hasSentry);
|
|
527
|
+
results.sentryCodemod = sentryResult.ok;
|
|
528
|
+
if (flags.skipSentry) results.sentrySkippedReason = 'skipped';
|
|
529
|
+
else if (!hasSentry) results.sentrySkippedReason = 'no @sentry/nextjs';
|
|
530
|
+
await maybePause(flags, 'sentry-codemod');
|
|
531
|
+
|
|
532
|
+
results.build = stepBuild(cwd, flags).ok;
|
|
533
|
+
} catch (err) {
|
|
534
|
+
log(`FATAL: ${err.message}`);
|
|
535
|
+
process.exitCode = 1;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
stepReport(cwd, results);
|
|
539
|
+
log('upgrade-to-2 done');
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
module.exports = { transform };
|
|
543
|
+
|
|
544
|
+
if (require.main === module) {
|
|
545
|
+
transform().catch((err) => {
|
|
546
|
+
console.error(err);
|
|
547
|
+
process.exit(1);
|
|
548
|
+
});
|
|
549
|
+
}
|
package/commands/codemod.ts
CHANGED