From afad13eb83f94c516d01f47a9bcec0f15340654d Mon Sep 17 00:00:00 2001 From: useon Date: Tue, 16 Sep 2025 16:47:27 +0900 Subject: [PATCH 01/16] =?UTF-8?q?chore:=20=EA=B5=AD=EC=A0=9C=ED=99=94=20?= =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=B8=8C=EB=9F=AC=EB=A6=AC=20=EC=84=A4?= =?UTF-8?q?=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 155 ++++++++++++++++++++++++++++++++++++++++++++-- package.json | 4 ++ 2 files changed, 155 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1bbc07d4..91ea5576 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,11 +13,15 @@ "axios": "^1.7.9", "clsx": "^2.1.1", "framer-motion": "^12.23.11", + "i18next": "^25.5.2", + "i18next-browser-languagedetector": "^8.2.0", + "i18next-http-backend": "^3.0.2", "pako": "^2.1.0", "qrcode.react": "^4.2.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-ga4": "^2.1.0", + "react-i18next": "^15.7.3", "react-icons": "^5.4.0", "react-router-dom": "^7.1.0", "vite-bundle-visualizer": "^1.2.1" @@ -331,10 +335,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", - "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", - "dev": true, + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -4405,6 +4408,15 @@ } } }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -6173,6 +6185,15 @@ "node": ">=18" } }, + "node_modules/html-parse-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz", + "integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==", + "license": "MIT", + "dependencies": { + "void-elements": "3.1.0" + } + }, "node_modules/html-tags": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", @@ -6214,6 +6235,55 @@ "node": ">= 14" } }, + "node_modules/i18next": { + "version": "25.5.2", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.5.2.tgz", + "integrity": "sha512-lW8Zeh37i/o0zVr+NoCHfNnfvVw+M6FQbRp36ZZ/NyHDJ3NJVpp2HhAUyU9WafL5AssymNoOjMRB48mmx2P6Hw==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.6" + }, + "peerDependencies": { + "typescript": "^5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/i18next-browser-languagedetector": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.2.0.tgz", + "integrity": "sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.2" + } + }, + "node_modules/i18next-http-backend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-3.0.2.tgz", + "integrity": "sha512-PdlvPnvIp4E1sYi46Ik4tBYh/v/NbYfFFgTjkwFl0is8A18s7/bx9aXqsrOax9WUbeNS6mD2oix7Z0yGGf6m5g==", + "license": "MIT", + "dependencies": { + "cross-fetch": "4.0.0" + } + }, "node_modules/iconv-lite": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", @@ -7624,6 +7694,48 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "license": "MIT" }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-releases": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", @@ -8587,6 +8699,32 @@ "integrity": "sha512-ZKS7PGNFqqMd3PJ6+C2Jtz/o1iU9ggiy8Y8nUeksgVuvNISbmrQtJiZNvC/TjDsqD0QlU5Wkgs7i+w9+OjHhhQ==", "license": "MIT" }, + "node_modules/react-i18next": { + "version": "15.7.3", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.7.3.tgz", + "integrity": "sha512-AANws4tOE+QSq/IeMF/ncoHlMNZaVLxpa5uUGW1wjike68elVYr0018L9xYoqBr1OFO7G7boDPrbn0HpMCJxTw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.27.6", + "html-parse-stringify": "^3.0.1" + }, + "peerDependencies": { + "i18next": ">= 25.4.1", + "react": ">= 16.8.0", + "typescript": "^5" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, "node_modules/react-icons": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.4.0.tgz", @@ -11803,6 +11941,15 @@ } } }, + "node_modules/void-elements": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz", + "integrity": "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", diff --git a/package.json b/package.json index e8c35368..bc5dd6e3 100644 --- a/package.json +++ b/package.json @@ -23,11 +23,15 @@ "axios": "^1.7.9", "clsx": "^2.1.1", "framer-motion": "^12.23.11", + "i18next": "^25.5.2", + "i18next-browser-languagedetector": "^8.2.0", + "i18next-http-backend": "^3.0.2", "pako": "^2.1.0", "qrcode.react": "^4.2.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-ga4": "^2.1.0", + "react-i18next": "^15.7.3", "react-icons": "^5.4.0", "react-router-dom": "^7.1.0", "vite-bundle-visualizer": "^1.2.1" From c8cfc46726c58001ea0d06f631875a8cfaeec5c2 Mon Sep 17 00:00:00 2001 From: useon Date: Tue, 16 Sep 2025 17:51:33 +0900 Subject: [PATCH 02/16] =?UTF-8?q?feat:=20i18next=20=EC=B4=88=EA=B8=B0?= =?UTF-8?q?=ED=99=94=20=EB=B0=8F=20=EC=96=B8=EC=96=B4=20=EA=B0=90=EC=A7=80?= =?UTF-8?q?/HTTP=20=EB=B0=B1=EC=97=94=EB=93=9C=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/i18n.ts | 31 +++++++++++++++++++++++++++++++ src/main.tsx | 1 + 2 files changed, 32 insertions(+) create mode 100644 src/i18n.ts diff --git a/src/i18n.ts b/src/i18n.ts new file mode 100644 index 00000000..a7da32f7 --- /dev/null +++ b/src/i18n.ts @@ -0,0 +1,31 @@ +import i18n from 'i18next'; +import { initReactI18next } from 'react-i18next'; +import LanguageDetector from 'i18next-browser-languagedetector'; +import HttpApi from 'i18next-http-backend'; + +i18n + .use(HttpApi) // 서버에서 번역 파일을 불러오기 + .use(LanguageDetector) // 사용자의 브라우저 언어 감지 + .use(initReactI18next) // i18n 인스턴스를 react-i18next에 전달 + .init({ + supportedLngs: ['ko', 'en'], // 지원할 언어 목록 + fallbackLng: 'ko', // 감지된 언어를 사용할 수 없을 때 사용할 기본 언어 + + // 언어를 감지하는 순서와 방법 + detection: { + order: ['path', 'localStorage', 'navigator'], + caches: ['localStorage'], + }, + + // 번역 파일을 불러올 위치 + backend: { + loadPath: '/locales/{{lng}}/translation.json', + }, + + // React와 함께 사용할 때의 옵션 + react: { + useSuspense: true, // 비동기 번역 파일 로딩을 위해 필요 + }, + }); + +export default i18n; diff --git a/src/main.tsx b/src/main.tsx index a263a75f..3cee194a 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -5,6 +5,7 @@ import { GlobalPortal } from './util/GlobalPortal'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import router from './routes/routes.tsx'; import './index.css'; +import './i18n'; import { setupGoogleAnalytics } from './util/setupGoogleAnalytics.tsx'; // Functions that calls msw mocking worker From 9accb6fd57a20d8235658f7a7b3a59905323a352 Mon Sep 17 00:00:00 2001 From: useon Date: Tue, 16 Sep 2025 17:54:20 +0900 Subject: [PATCH 03/16] =?UTF-8?q?feat:=20=EA=B5=AD=EC=A0=9C=ED=99=94=20?= =?UTF-8?q?=EB=9D=BC=EC=9A=B0=ED=8C=85=20=EB=9E=98=ED=8D=BC=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/LanguageWrapper.tsx | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/routes/LanguageWrapper.tsx diff --git a/src/routes/LanguageWrapper.tsx b/src/routes/LanguageWrapper.tsx new file mode 100644 index 00000000..cf7dc113 --- /dev/null +++ b/src/routes/LanguageWrapper.tsx @@ -0,0 +1,20 @@ +import { useEffect } from 'react'; +import { Outlet, useParams } from 'react-router-dom'; +import i18n from '../i18n'; + +const supportedLangs = ['ko', 'en']; + +export default function LanguageWrapper() { + const { lang } = useParams(); + + useEffect(() => { + // URL에 lang 파라미터가 없으면 'ko'를 기본값으로 사용 + const currentLang = lang || 'ko'; + + if (supportedLangs.includes(currentLang) && i18n.language !== currentLang) { + i18n.changeLanguage(currentLang); + } + }, [lang]); + + return ; +} From f3007035d531ca2a5c5fd0e0b623705ade4c6bbb Mon Sep 17 00:00:00 2001 From: useon Date: Tue, 16 Sep 2025 17:59:07 +0900 Subject: [PATCH 04/16] =?UTF-8?q?feat:=20=EC=A4=91=EC=B2=A9=20=EB=9D=BC?= =?UTF-8?q?=EC=9A=B0=ED=8C=85=20=EA=B5=AC=EC=A1=B0=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EB=B0=8F=20=EA=B5=AD=EC=A0=9C=ED=99=94=20=EB=9D=BC?= =?UTF-8?q?=EC=9A=B0=ED=8C=85=20=EB=9E=98=ED=8D=BC=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/routes/routes.tsx | 51 ++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/src/routes/routes.tsx b/src/routes/routes.tsx index 87e3f1dd..c60f99d0 100644 --- a/src/routes/routes.tsx +++ b/src/routes/routes.tsx @@ -13,50 +13,51 @@ import FeedbackTimerPage from '../page/TimerPage/FeedbackTimerPage'; import LandingPage from '../page/LandingPage/LandingPage'; import TableSharingPage from '../page/TableSharingPage/TableSharingPage'; import DebateEndPage from '../page/DebateEndPage/DebateEndPage'; +import LanguageWrapper from './LanguageWrapper'; -const routesConfig = [ +const appRoutes = [ { - path: '/home', + path: 'home', element: , requiresAuth: false, }, { - path: '/', + path: '', element: , requiresAuth: true, }, { - path: '/composition', + path: 'composition', element: , requiresAuth: false, }, { - path: '/overview/:type/:id', + path: 'overview/:type/:id', element: , requiresAuth: false, }, { - path: '/table/customize/:id', + path: 'table/customize/:id', element: , requiresAuth: false, }, { - path: '/table/customize/:id/end', + path: 'table/customize/:id/end', element: , requiresAuth: true, }, { - path: '/table/customize/:id/end/feedback', + path: 'table/customize/:id/end/feedback', element: , requiresAuth: true, }, { - path: '/oauth', + path: 'oauth', element: , requiresAuth: false, }, { - path: '/share', + path: 'share', element: , requiresAuth: false, }, @@ -67,6 +68,16 @@ const routesConfig = [ }, ]; +// 인증 보호 로직을 적용한 라우트 +const protectedAppRoutes = appRoutes.map((route) => ({ + ...route, + element: route.requiresAuth ? ( + {route.element} + ) : ( + route.element + ), +})); + const router = createBrowserRouter([ { element: ( @@ -75,14 +86,18 @@ const router = createBrowserRouter([ ), - children: routesConfig.map((route) => ({ - ...route, - element: route.requiresAuth ? ( - {route.element} - ) : ( - route.element - ), - })), + children: [ + { + path: '/', + element: , + children: protectedAppRoutes, // 기본 언어(ko) 라우트 + }, + { + path: ':lang', // 다른 언어 라우트 + element: , + children: protectedAppRoutes, + }, + ], }, ]); From 595e717aa64647029f9809e195d6c3af66caaba1 Mon Sep 17 00:00:00 2001 From: useon Date: Tue, 7 Oct 2025 15:46:16 +0900 Subject: [PATCH 05/16] =?UTF-8?q?chore:=20=ED=95=84=EC=9A=94=ED=95=9C=20?= =?UTF-8?q?=EB=B0=94=EB=B2=A8=20=EC=84=A4=EC=A0=95=20=EB=B0=8F=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=A6=BD=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 585 +++++++++++++++++++++++++++++++++++++--------- package.json | 12 +- 2 files changed, 485 insertions(+), 112 deletions(-) diff --git a/package-lock.json b/package-lock.json index 91ea5576..24de3346 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,10 @@ "vite-bundle-visualizer": "^1.2.1" }, "devDependencies": { + "@babel/generator": "^7.28.3", + "@babel/parser": "^7.28.4", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", "@chromatic-com/storybook": "^3.2.2", "@eslint/js": "^9.15.0", "@storybook/addon-essentials": "^8.6.0", @@ -40,7 +44,10 @@ "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.1.0", "@testing-library/user-event": "^14.5.2", + "@types/babel__traverse": "^7.28.0", + "@types/glob": "^8.1.0", "@types/jest": "^29.5.14", + "@types/node": "^24.6.0", "@types/pako": "^2.0.3", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", @@ -58,6 +65,7 @@ "eslint-plugin-react-refresh": "^0.4.14", "eslint-plugin-storybook": "^0.11.1", "eslint-plugin-tailwindcss": "^3.17.5", + "glob": "^11.0.3", "globals": "^15.12.0", "jsdom": "^25.0.1", "msw": "^2.7.0", @@ -70,6 +78,7 @@ "stylelint-config-recommended": "^14.0.1", "stylelint-config-tailwindcss": "^0.0.7", "tailwindcss": "^3.4.16", + "ts-node": "^10.9.2", "typescript": "^5.7.2", "typescript-eslint": "^8.15.0", "vite": "^6.0.1", @@ -167,16 +176,16 @@ } }, "node_modules/@babel/generator": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz", - "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.26.3", - "@babel/types": "^7.26.3", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" }, "engines": { @@ -200,6 +209,16 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-module-imports": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", @@ -287,13 +306,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.2.tgz", - "integrity": "sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.27.1" + "@babel/types": "^7.28.4" }, "bin": { "parser": "bin/babel-parser.js" @@ -359,38 +378,28 @@ } }, "node_modules/@babel/traverse": { - "version": "7.26.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz", - "integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.3", - "@babel/parser": "^7.26.3", - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.3", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/types": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.1.tgz", - "integrity": "sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", "dev": true, "license": "MIT", "dependencies": { @@ -489,6 +498,30 @@ "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" } }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@csstools/css-parser-algorithms": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", @@ -1317,6 +1350,29 @@ "@types/node": ">=18" } }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -1400,6 +1456,60 @@ } } }, + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/magic-string": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", @@ -1413,19 +1523,48 @@ "node": ">=12" } }, + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@joshwooding/vite-plugin-react-docgen-typescript/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -1438,16 +1577,6 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", @@ -1456,9 +1585,9 @@ "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, "license": "MIT", "dependencies": { @@ -2816,6 +2945,34 @@ "@testing-library/dom": ">=7.21.4" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/aria-query": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", @@ -2859,13 +3016,13 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.20.7" + "@babel/types": "^7.28.2" } }, "node_modules/@types/cookie": { @@ -2888,6 +3045,17 @@ "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", "license": "MIT" }, + "node_modules/@types/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-IO+MJPVhoqz+28h1qLAcBEH2+xHMK6MTyHJc7MTnnYb6wsoLR29POVGJ7LycmVXIqyy/4/2ShP5sUwTXuOwb/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/minimatch": "^5.1.2", + "@types/node": "*" + } + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -2981,14 +3149,21 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/node": { - "version": "22.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", - "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", + "version": "24.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.6.0.tgz", + "integrity": "sha512-F1CBxgqwOMc4GKJ7eY22hWhBVQuMYTtqI8L0FcszYcpYX0fzfDGpez22Xau8Mgm7O9fI+zA/TYIdq3tGWfweBA==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.20.0" + "undici-types": "~7.13.0" } }, "node_modules/@types/pako": { @@ -3481,6 +3656,19 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/agent-base": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.2.tgz", @@ -4408,6 +4596,13 @@ } } }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/cross-fetch": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", @@ -4681,6 +4876,16 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -5695,13 +5900,13 @@ } }, "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "dev": true, "license": "ISC", "dependencies": { - "cross-spawn": "^7.0.0", + "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" }, "engines": { @@ -5885,22 +6090,25 @@ } }, "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz", + "integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==", "dev": true, "license": "ISC", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.0.3", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" + "path-scurry": "^2.0.0" }, "bin": { "glob": "dist/esm/bin.mjs" }, + "engines": { + "node": "20 || >=22" + }, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -5917,27 +6125,17 @@ "node": ">=10.13.0" } }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/glob/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "@isaacs/brace-expansion": "^5.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -6890,19 +7088,19 @@ } }, "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, + "engines": { + "node": "20 || >=22" + }, "funding": { "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" } }, "node_modules/jest-diff": { @@ -7413,6 +7611,13 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, "node_modules/map-or-similar": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", @@ -8056,28 +8261,31 @@ "license": "MIT" }, "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": ">=16 || 14 >=14.18" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz", + "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==", "dev": true, - "license": "ISC" + "license": "ISC", + "engines": { + "node": "20 || >=22" + } }, "node_modules/path-to-regexp": { "version": "6.3.0", @@ -9956,6 +10164,93 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/sucrase/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sucrase/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/sucrase/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/sucrase/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sucrase/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -10367,6 +10662,57 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -10569,9 +10915,9 @@ } }, "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.13.0.tgz", + "integrity": "sha512-Ov2Rr9Sx+fRgagJ5AX0qvItZG/JKKoBRAVITs1zk7IqZGTJUwgUr7qoYBpWwakpWilTZFM98rG/AFRocu10iIQ==", "dev": true, "license": "MIT" }, @@ -10685,6 +11031,13 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, "node_modules/vite": { "version": "6.3.5", "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", @@ -12229,9 +12582,9 @@ } }, "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", "engines": { @@ -12391,6 +12744,16 @@ "node": ">=8" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index bc5dd6e3..a1f3403d 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "storybook": "storybook dev -p 6006", "build-storybook": "storybook build", "test": "vitest", - "chromatic": "npx chromatic --project-token=chpt_a6dc39eba6488b2" + "chromatic": "npx chromatic --project-token=chpt_a6dc39eba6488b2", + "i18n:transform": "ts-node scripts/i18nTransform.ts" }, "dependencies": { "@tanstack/eslint-plugin-query": "^5.62.9", @@ -37,6 +38,10 @@ "vite-bundle-visualizer": "^1.2.1" }, "devDependencies": { + "@babel/generator": "^7.28.3", + "@babel/parser": "^7.28.4", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", "@chromatic-com/storybook": "^3.2.2", "@eslint/js": "^9.15.0", "@storybook/addon-essentials": "^8.6.0", @@ -50,7 +55,10 @@ "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.1.0", "@testing-library/user-event": "^14.5.2", + "@types/babel__traverse": "^7.28.0", + "@types/glob": "^8.1.0", "@types/jest": "^29.5.14", + "@types/node": "^24.6.0", "@types/pako": "^2.0.3", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", @@ -68,6 +76,7 @@ "eslint-plugin-react-refresh": "^0.4.14", "eslint-plugin-storybook": "^0.11.1", "eslint-plugin-tailwindcss": "^3.17.5", + "glob": "^11.0.3", "globals": "^15.12.0", "jsdom": "^25.0.1", "msw": "^2.7.0", @@ -80,6 +89,7 @@ "stylelint-config-recommended": "^14.0.1", "stylelint-config-tailwindcss": "^0.0.7", "tailwindcss": "^3.4.16", + "ts-node": "^10.9.2", "typescript": "^5.7.2", "typescript-eslint": "^8.15.0", "vite": "^6.0.1", From 788275996d8dcdb6fdcff1671e53b4d18f5cbf45 Mon Sep 17 00:00:00 2001 From: useon Date: Tue, 7 Oct 2025 15:56:48 +0900 Subject: [PATCH 06/16] =?UTF-8?q?feat:=20=ED=8C=8C=EC=9D=BC=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=9C=A0=ED=8B=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/utils/fileUtils.ts | 88 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 scripts/utils/fileUtils.ts diff --git a/scripts/utils/fileUtils.ts b/scripts/utils/fileUtils.ts new file mode 100644 index 00000000..0ef8933c --- /dev/null +++ b/scripts/utils/fileUtils.ts @@ -0,0 +1,88 @@ +import * as fsp from 'fs/promises'; +import * as path from 'path'; + +/** 파일을 읽어서 문자열로 반환 */ +export function readFile(filePath: string): Promise { + return fsp.readFile(filePath, 'utf8'); +} + +/** 파일을 JSON으로 파싱 */ +export async function readJSON(filePath: string): Promise { + const content = await readFile(filePath); + return JSON.parse(content) as T; +} + +/** 디렉토리가 없으면 생성하고, 파일이 없으면 빈 파일 생성 (ensureFile) */ +export async function ensureFile(filePath: string): Promise { + const dir = path.dirname(filePath); + + // 1. 디렉토리 구조 보장 (writeFile에서 mkdir을 처리하므로, 여기서는 fsp.access를 사용) + try { + // 디렉토리가 존재하는지 확인 + await fsp.access(dir); + } catch { + // 디렉토리가 없으면 생성 + await fsp.mkdir(dir, { recursive: true }); + } + // 2. 파일이 존재하는지 확인하고, 없다면 빈 파일 생성 + try { + await fsp.access(filePath); + } catch { + // 파일이 없으면 catch 블록으로 진입, 빈 JSON 파일 생성 + await fsp.writeFile(filePath, '{}', 'utf8'); + } +} + +/** 문자열을 파일로 저장 */ +export async function writeFile(filePath: string, data: string): Promise { + console.log(`[writeFile] 파일 쓰기 시작: ${filePath}`); + const dir = path.dirname(filePath); + + await fsp.mkdir(dir, { recursive: true }).catch(() => {}); + + await fsp.writeFile(filePath, data, 'utf8'); + console.log(`[writeFile] 파일 쓰기 완료: ${filePath}`); +} + +/** JSON 데이터를 파일로 저장 */ +export async function writeJSON( + filePath: string, + data: unknown, +): Promise { + console.log(`[writeJSON] JSON 데이터 저장 시작: ${filePath}`); + await writeFile(filePath, JSON.stringify(data, null, 2)); + console.log(`[writeJSON] JSON 데이터 저장 완료: ${filePath}`); +} + +/** 특정 확장자 파일들을 재귀적으로 찾기 */ +export async function getAllFiles( + dir: string, + ext: string, + fileList: string[] = [], +): Promise { + try { + // 비동기적으로 디렉토리 내용 읽기 + const entries = await fsp.readdir(dir, { withFileTypes: true }); + + // 모든 재귀 호출을 Promise.all로 병렬 처리 + const promises = entries.map(async (entry) => { + const fullPath = path.join(dir, entry.name); + + if (entry.isDirectory()) { + // 디렉토리인 경우, 비동기 재귀 호출을 하고 결과 병합 + const nestedFiles = await getAllFiles(fullPath, ext); + fileList.push(...nestedFiles); + } else if (entry.isFile() && entry.name.endsWith(ext)) { + // 파일인 경우, 리스트에 추가 + fileList.push(fullPath); + } + }); + + // 모든 비동기 작업(하위 디렉토리 순회)이 완료될 때까지 기다림 + await Promise.all(promises); + } catch (err) { + console.error(`에러 발생 디렉토리 ${dir}:`, err); + } + + return fileList; +} From 8a896370fdea0e662c1aab3ac21b0cb61942005e Mon Sep 17 00:00:00 2001 From: useon Date: Tue, 7 Oct 2025 15:58:50 +0900 Subject: [PATCH 07/16] =?UTF-8?q?feat:=20ATS=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EB=B0=8F=20=EA=B5=AD=EC=A0=9C=ED=99=94=20=ED=9B=85=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80,=20t=20wrapper=20=EC=9C=A0=ED=8B=B8=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/utils/astUtils.ts | 184 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 scripts/utils/astUtils.ts diff --git a/scripts/utils/astUtils.ts b/scripts/utils/astUtils.ts new file mode 100644 index 00000000..ddd8c4f9 --- /dev/null +++ b/scripts/utils/astUtils.ts @@ -0,0 +1,184 @@ +import * as parser from '@babel/parser'; +import type { NodePath } from '@babel/traverse'; +import _traverse from '@babel/traverse'; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const traverse = (_traverse as any).default; +import _generate from '@babel/generator'; +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const generate = (_generate as any).default; +import * as t from '@babel/types'; + +const KOREAN_REGEX = /[가-힣]/; + +/** + * 코드 문자열을 파싱하여 AST로 변환 + */ +export function parseCode(code: string) { + return parser.parse(code, { + sourceType: 'module', + plugins: ['jsx', 'typescript'], + }); +} + +/** + * AST에서 한글 문자열 탐색 및 변환 + */ +export function transformAST(ast: t.File) { + const koreanKeys = new Set(); + const componentsToModify = new Set(); + let hasUseTranslationImport = false; + + // 1️. 한글 문자열 탐색 + traverse(ast, { + JSXText(path) { + const value = path.node.value.trim(); + if (value && KOREAN_REGEX.test(value)) { + koreanKeys.add(value); + const component = path.findParent( + (p) => + p.isFunctionDeclaration() || + p.isArrowFunctionExpression() || + p.isFunctionExpression(), + ); + if (component) componentsToModify.add(component); + } + }, + StringLiteral(path) { + const value = path.node.value.trim(); + if ( + value && + KOREAN_REGEX.test(value) && + path.parent.type !== 'ImportDeclaration' && + path.parent.type !== 'ExportNamedDeclaration' && + !( + path.parent.type === 'ObjectProperty' && path.parent.key === path.node + ) + ) { + koreanKeys.add(value); + const component = path.findParent( + (p) => + p.isFunctionDeclaration() || + p.isArrowFunctionExpression() || + p.isFunctionExpression(), + ); + if (component) componentsToModify.add(component); + } + }, + ImportDeclaration(path) { + if (path.node.source.value === 'react-i18next') { + hasUseTranslationImport = true; + } + }, + }); + + // 2️. useTranslation import 추가 + if (koreanKeys.size > 0 && !hasUseTranslationImport) { + const importDecl = t.importDeclaration( + [ + t.importSpecifier( + t.identifier('useTranslation'), + t.identifier('useTranslation'), + ), + ], + t.stringLiteral('react-i18next'), + ); + ast.program.body.unshift(importDecl); + } + + // 3️. 각 컴포넌트에 const { t } = useTranslation() 추가 + componentsToModify.forEach((componentPath) => { + const bodyPath = componentPath.get('body'); + + if (Array.isArray(bodyPath) || !bodyPath.isBlockStatement()) { + return; + } + + let hasHook = false; + bodyPath.get('body').forEach((stmt) => { + if (stmt.isVariableDeclaration()) { + const declaration = stmt.node.declarations[0]; + if ( + declaration?.init?.type === 'CallExpression' && + t.isIdentifier(declaration.init.callee) && + declaration.init.callee.name === 'useTranslation' + ) { + hasHook = true; + } + } + }); + + if (!hasHook) { + const hookDecl = t.variableDeclaration('const', [ + t.variableDeclarator( + t.objectPattern([ + t.objectProperty(t.identifier('t'), t.identifier('t'), false, true), + ]), + t.callExpression(t.identifier('useTranslation'), []), + ), + ]); + bodyPath.unshiftContainer('body', hookDecl); + } + }); + + // 4️. 한글 텍스트를 t('...')로 감싸기 + traverse(ast, { + JSXText(path) { + const value = path.node.value.trim(); + if (value && koreanKeys.has(value)) { + const parent = path.findParent( + (p) => + p.isCallExpression() && + t.isIdentifier(p.node.callee) && + p.node.callee.name === 't', + ); + if (parent) return; + + const tCall = t.callExpression(t.identifier('t'), [ + t.stringLiteral(value), + ]); + path.replaceWith(t.jsxExpressionContainer(tCall)); + } + }, + StringLiteral(path) { + const value = path.node.value.trim(); + if ( + path.parent.type === 'CallExpression' && + t.isIdentifier(path.parent.callee) && + path.parent.callee.name === 't' + ) { + return; + } + + if ( + koreanKeys.has(value) && + path.parent.type !== 'ImportDeclaration' && + path.parent.type !== 'ExportNamedDeclaration' + ) { + if (path.parent.type === 'JSXAttribute') { + const tCall = t.callExpression(t.identifier('t'), [ + t.stringLiteral(value), + ]); + path.replaceWith(t.jsxExpressionContainer(tCall)); + } else { + const tCall = t.callExpression(t.identifier('t'), [ + t.stringLiteral(value), + ]); + path.replaceWith(tCall); + } + } + }, + }); + + return koreanKeys; +} + +/** + * AST를 코드 문자열로 다시 변환 + */ +export function generateCode(ast: t.File) { + const { code } = generate(ast, { + retainLines: true, + jsescOption: { minimal: true }, + }); + return code; +} From b859bc9c9950acc2b6ad244eb8e34788555384d1 Mon Sep 17 00:00:00 2001 From: useon Date: Tue, 7 Oct 2025 15:59:32 +0900 Subject: [PATCH 08/16] =?UTF-8?q?feat:=20=ED=95=9C=EA=B8=80=20=ED=82=A4?= =?UTF-8?q?=EB=A5=BC=20=EA=B8=B0=EC=A4=80=EC=9C=BC=EB=A1=9C=20=EA=B0=81=20?= =?UTF-8?q?=EC=96=B8=EC=96=B4=20JSON=EC=97=90=20=ED=82=A4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EC=9C=A0=ED=8B=B8=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/utils/translationUtils.ts | 45 +++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 scripts/utils/translationUtils.ts diff --git a/scripts/utils/translationUtils.ts b/scripts/utils/translationUtils.ts new file mode 100644 index 00000000..fd0c61a4 --- /dev/null +++ b/scripts/utils/translationUtils.ts @@ -0,0 +1,45 @@ +import * as path from 'path'; +import { ensureFile, readJSON, writeJSON } from './fileUtils.ts'; + +interface TranslationUpdateOptions { + languages?: string[]; + baseDir?: string; +} + +/** + * 한글 키를 기준으로 각 언어 JSON에 키 추가 + * - 중복 키는 건너뜀 + * - en은 빈 문자열, ko는 원문 그대로 + */ +export async function updateTranslationFiles( + keys: Set, + { + languages = ['ko', 'en'], + baseDir = 'public/locales', + }: TranslationUpdateOptions = {}, +) { + if (keys.size === 0) return; + + console.log('번역 파일을 업데이트합니다...'); + + for (const lang of languages) { + const filePath = path.join(baseDir, lang, 'translation.json'); + await ensureFile(filePath); + const translations = await readJSON>(filePath); + + let updated = false; + for (const key of keys) { + if (!(key in translations)) { + translations[key] = lang === 'ko' ? key : ''; + console.log(`키 추가: '${key}' (${lang}/translation.json)`); + updated = true; + } + } + + if (updated) { + await writeJSON(filePath, translations); + } + } + + console.log('번역 파일 업데이트가 완료되었습니다.\n'); +} From 4bc752562177df669442bc010eb3bf76c787964d Mon Sep 17 00:00:00 2001 From: useon Date: Tue, 7 Oct 2025 16:00:49 +0900 Subject: [PATCH 09/16] =?UTF-8?q?feat:=20React=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EC=9D=98=20=ED=95=9C=EA=B8=80=20=ED=85=8D?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9E=90=EB=8F=99=20=EB=B3=80=ED=99=98=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/i18nTransform.ts | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 scripts/i18nTransform.ts diff --git a/scripts/i18nTransform.ts b/scripts/i18nTransform.ts new file mode 100644 index 00000000..46bfccd0 --- /dev/null +++ b/scripts/i18nTransform.ts @@ -0,0 +1,42 @@ +import * as fs from 'fs/promises'; +import { glob } from 'glob'; +import { parseCode, transformAST, generateCode } from './utils/astUtils.ts'; +import { updateTranslationFiles } from './utils/translationUtils.ts'; + +async function processFile(filePath: string) { + console.log(`\n파일 처리 중: ${filePath}`); + const originalCode = await fs.readFile(filePath, 'utf-8'); + const ast = parseCode(originalCode); + + const koreanKeys = transformAST(ast); + if (koreanKeys.size === 0) { + console.log('한글 텍스트를 찾지 못했습니다.'); + return; + } + + await updateTranslationFiles(koreanKeys); + + const newCode = generateCode(ast); + if (newCode !== originalCode) { + await fs.writeFile(filePath, newCode, 'utf-8'); + console.log(`파일 업데이트 완료: ${filePath}`); + } else { + console.log('변경 사항이 없습니다.'); + } +} + +async function main() { + const files = await glob('src/**/*.tsx'); + if (files.length === 0) { + console.log('.tsx 파일을 찾지 못했습니다.'); + return; + } + + for (const file of files) { + await processFile(file); + } + + console.log('\ni18n 변환 작업이 완료되었습니다.'); +} + +main().catch(console.error); From 5f02869a79049ae7f939db014d11b48610023c03 Mon Sep 17 00:00:00 2001 From: useon Date: Tue, 7 Oct 2025 16:20:51 +0900 Subject: [PATCH 10/16] =?UTF-8?q?fix:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=EA=B3=BC=20=EC=8A=A4=ED=86=A0=EB=A6=AC?= =?UTF-8?q?=EB=B6=81=20=ED=8C=8C=EC=9D=BC=EC=9D=B4=20=ED=8F=AC=ED=95=A8?= =?UTF-8?q?=EB=90=98=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/i18nTransform.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/i18nTransform.ts b/scripts/i18nTransform.ts index 46bfccd0..54e2e578 100644 --- a/scripts/i18nTransform.ts +++ b/scripts/i18nTransform.ts @@ -26,7 +26,9 @@ async function processFile(filePath: string) { } async function main() { - const files = await glob('src/**/*.tsx'); + const files = await glob('src/**/*.tsx', { + ignore: ['src/**/*.test.tsx', 'src/**/*.stories.tsx'], + }); if (files.length === 0) { console.log('.tsx 파일을 찾지 못했습니다.'); return; From c0eb304df0678fce890ea67381de6fb4bf275619 Mon Sep 17 00:00:00 2001 From: useon Date: Wed, 8 Oct 2025 16:45:06 +0900 Subject: [PATCH 11/16] =?UTF-8?q?refactor:=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=ED=8C=90=EB=B3=84=20=EB=A1=9C=EC=A7=81=EC=9D=84=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=ED=95=98=EC=97=AC=20=EC=97=AC=EB=9F=AC=20?= =?UTF-8?q?=ED=98=95=ED=83=9C=EC=97=90=20=EB=8C=80=EC=9D=91=ED=95=A0=20?= =?UTF-8?q?=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/utils/astUtils.ts | 53 +++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/scripts/utils/astUtils.ts b/scripts/utils/astUtils.ts index ddd8c4f9..345afe2c 100644 --- a/scripts/utils/astUtils.ts +++ b/scripts/utils/astUtils.ts @@ -20,6 +20,40 @@ export function parseCode(code: string) { }); } +/** + * 리액트 컴포넌트 함수인지 판별 + */ +function isReactComponentFunction(path: NodePath): boolean { + // 함수 선언문 + if (path.isFunctionDeclaration()) { + return path.node.id?.name?.[0] === path.node.id?.name?.[0]?.toUpperCase(); + } + + // 화살표 함수 표현식 또는 함수 표현식 + if (path.isArrowFunctionExpression() || path.isFunctionExpression()) { + const parent = path.parentPath; + + // 변수 선언문 + if (parent?.isVariableDeclarator()) { + const varName = (parent.node.id as t.Identifier)?.name; + return /^[A-Z]/.test(varName); + } + + // 합성 컴포넌트 + if (parent?.isAssignmentExpression()) { + const left = parent.get('left'); + if (left.isMemberExpression()) { + const property = left.get('property'); + if (property.isIdentifier()) { + return /^[A-Z]/.test(property.node.name); + } + } + } + } + + return false; +} + /** * AST에서 한글 문자열 탐색 및 변환 */ @@ -34,12 +68,7 @@ export function transformAST(ast: t.File) { const value = path.node.value.trim(); if (value && KOREAN_REGEX.test(value)) { koreanKeys.add(value); - const component = path.findParent( - (p) => - p.isFunctionDeclaration() || - p.isArrowFunctionExpression() || - p.isFunctionExpression(), - ); + const component = path.findParent((p) => isReactComponentFunction(p)); if (component) componentsToModify.add(component); } }, @@ -55,12 +84,7 @@ export function transformAST(ast: t.File) { ) ) { koreanKeys.add(value); - const component = path.findParent( - (p) => - p.isFunctionDeclaration() || - p.isArrowFunctionExpression() || - p.isFunctionExpression(), - ); + const component = path.findParent((p) => isReactComponentFunction(p)); if (component) componentsToModify.add(component); } }, @@ -88,10 +112,7 @@ export function transformAST(ast: t.File) { // 3️. 각 컴포넌트에 const { t } = useTranslation() 추가 componentsToModify.forEach((componentPath) => { const bodyPath = componentPath.get('body'); - - if (Array.isArray(bodyPath) || !bodyPath.isBlockStatement()) { - return; - } + if (Array.isArray(bodyPath) || !bodyPath.isBlockStatement()) return; let hasHook = false; bodyPath.get('body').forEach((stmt) => { From 87e9a1cfb98d1df48fcb4ea6be7609309de288a8 Mon Sep 17 00:00:00 2001 From: useon Date: Thu, 20 Nov 2025 00:01:50 +0900 Subject: [PATCH 12/16] =?UTF-8?q?feat:=20=ED=85=9C=ED=94=8C=EB=A6=BF=20?= =?UTF-8?q?=EB=A6=AC=ED=84=B0=EB=9F=B4=20=EC=9E=90=EB=8F=99=20=EB=B3=80?= =?UTF-8?q?=ED=99=98=20=EB=B0=8F=20=ED=82=A4=20=EC=B6=94=EC=B6=9C=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/utils/astUtils.ts | 86 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/scripts/utils/astUtils.ts b/scripts/utils/astUtils.ts index 345afe2c..1819366b 100644 --- a/scripts/utils/astUtils.ts +++ b/scripts/utils/astUtils.ts @@ -61,6 +61,11 @@ export function transformAST(ast: t.File) { const koreanKeys = new Set(); const componentsToModify = new Set(); let hasUseTranslationImport = false; + const templateLiteralsToTransform: { + path: NodePath; + i18nKey: string; + objectProperties: t.ObjectProperty[]; + }[] = []; // 1️. 한글 문자열 탐색 traverse(ast, { @@ -88,6 +93,69 @@ export function transformAST(ast: t.File) { if (component) componentsToModify.add(component); } }, + TemplateLiteral(path) { + const { quasis, expressions } = path.node; + const hasKorean = quasis.some((q) => KOREAN_REGEX.test(q.value.raw)); + if (!hasKorean) return; + + if ( + path.parent.type === 'CallExpression' && + t.isIdentifier(path.parent.callee) && + path.parent.callee.name === 't' + ) { + return; + } + + let i18nKey = ''; + const objectProperties: t.ObjectProperty[] = []; + + for (let i = 0; i < quasis.length; i++) { + i18nKey += quasis[i].value.raw; + if (i < expressions.length) { + const expr = expressions[i]; + let placeholderName: string; + + if (t.isIdentifier(expr)) { + placeholderName = expr.name; + } else if ( + t.isMemberExpression(expr) && + t.isIdentifier(expr.property) + ) { + placeholderName = expr.property.name; + } else { + placeholderName = `val${i}`; + } + + let finalName = placeholderName; + let count = 1; + while ( + objectProperties.some( + (p) => t.isIdentifier(p.key) && p.key.name === finalName, + ) + ) { + finalName = `${placeholderName}${count++}`; + } + + i18nKey += `{{${finalName}}}`; + objectProperties.push( + t.objectProperty( + t.identifier(finalName), + expr, + false, + t.isIdentifier(expr) && finalName === expr.name, + ), + ); + } + } + + koreanKeys.add(i18nKey); + const component = path.findParent((p) => isReactComponentFunction(p)); + if (component) { + componentsToModify.add(component); + } + + templateLiteralsToTransform.push({ path, i18nKey, objectProperties }); + }, ImportDeclaration(path) { if (path.node.source.value === 'react-i18next') { hasUseTranslationImport = true; @@ -141,7 +209,23 @@ export function transformAST(ast: t.File) { } }); - // 4️. 한글 텍스트를 t('...')로 감싸기 + // 4️. 템플릿 리터럴 변환 + templateLiteralsToTransform.forEach(({ path, i18nKey, objectProperties }) => { + const keyLiteral = t.stringLiteral(i18nKey); + if (objectProperties.length > 0) { + const interpolationObject = t.objectExpression(objectProperties); + const tCall = t.callExpression(t.identifier('t'), [ + keyLiteral, + interpolationObject, + ]); + path.replaceWith(tCall); + } else { + const tCall = t.callExpression(t.identifier('t'), [keyLiteral]); + path.replaceWith(tCall); + } + }); + + // 5️. 한글 텍스트를 t('...')로 감싸기 traverse(ast, { JSXText(path) { const value = path.node.value.trim(); From 52e762201cd0b6ee158be330a996c67753a0d564 Mon Sep 17 00:00:00 2001 From: useon Date: Sat, 22 Nov 2025 00:06:48 +0900 Subject: [PATCH 13/16] =?UTF-8?q?refactor:=20=EC=BB=B4=ED=8F=AC=EB=84=8C?= =?UTF-8?q?=ED=8A=B8=20=EB=82=B4=EB=B6=80=EC=97=90=20=EC=9E=88=EB=8A=94=20?= =?UTF-8?q?=ED=95=9C=EA=B8=80=20=EB=AC=B8=EC=9E=90=EC=97=B4=EB=A7=8C=20?= =?UTF-8?q?=EB=B3=80=ED=99=98=EB=90=98=EB=8F=84=EB=A1=9D=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/utils/astUtils.ts | 99 ++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 54 deletions(-) diff --git a/scripts/utils/astUtils.ts b/scripts/utils/astUtils.ts index 1819366b..719ca2ac 100644 --- a/scripts/utils/astUtils.ts +++ b/scripts/utils/astUtils.ts @@ -61,20 +61,31 @@ export function transformAST(ast: t.File) { const koreanKeys = new Set(); const componentsToModify = new Set(); let hasUseTranslationImport = false; + const simpleStringsToTransform: NodePath[] = []; const templateLiteralsToTransform: { path: NodePath; i18nKey: string; objectProperties: t.ObjectProperty[]; }[] = []; - // 1️. 한글 문자열 탐색 + // 1️. 한글 문자열 탐색 및 변환 대상 수집 traverse(ast, { JSXText(path) { const value = path.node.value.trim(); if (value && KOREAN_REGEX.test(value)) { - koreanKeys.add(value); const component = path.findParent((p) => isReactComponentFunction(p)); - if (component) componentsToModify.add(component); + if (component) { + const parentT = path.findParent( + (p) => + p.isCallExpression() && + p.get('callee').isIdentifier({ name: 't' }), + ); + if (parentT) return; + + simpleStringsToTransform.push(path); + koreanKeys.add(value); + componentsToModify.add(component); + } } }, StringLiteral(path) { @@ -88,9 +99,19 @@ export function transformAST(ast: t.File) { path.parent.type === 'ObjectProperty' && path.parent.key === path.node ) ) { - koreanKeys.add(value); const component = path.findParent((p) => isReactComponentFunction(p)); - if (component) componentsToModify.add(component); + if (component) { + const parentT = path.findParent( + (p) => + p.isCallExpression() && + p.get('callee').isIdentifier({ name: 't' }), + ); + if (parentT) return; + + simpleStringsToTransform.push(path); + koreanKeys.add(value); + componentsToModify.add(component); + } } }, TemplateLiteral(path) { @@ -106,6 +127,9 @@ export function transformAST(ast: t.File) { return; } + const component = path.findParent((p) => isReactComponentFunction(p)); + if (!component) return; + let i18nKey = ''; const objectProperties: t.ObjectProperty[] = []; @@ -149,11 +173,7 @@ export function transformAST(ast: t.File) { } koreanKeys.add(i18nKey); - const component = path.findParent((p) => isReactComponentFunction(p)); - if (component) { - componentsToModify.add(component); - } - + componentsToModify.add(component); templateLiteralsToTransform.push({ path, i18nKey, objectProperties }); }, ImportDeclaration(path) { @@ -225,53 +245,24 @@ export function transformAST(ast: t.File) { } }); - // 5️. 한글 텍스트를 t('...')로 감싸기 - traverse(ast, { - JSXText(path) { - const value = path.node.value.trim(); - if (value && koreanKeys.has(value)) { - const parent = path.findParent( - (p) => - p.isCallExpression() && - t.isIdentifier(p.node.callee) && - p.node.callee.name === 't', - ); - if (parent) return; + // 5️. 컴포넌트 내부 한글 텍스트 t()로 감싸기 + simpleStringsToTransform.forEach((path) => { + const value = + path.node.type === 'JSXText' + ? path.node.value.trim() + : (path.node as t.StringLiteral).value; - const tCall = t.callExpression(t.identifier('t'), [ - t.stringLiteral(value), - ]); - path.replaceWith(t.jsxExpressionContainer(tCall)); - } - }, - StringLiteral(path) { - const value = path.node.value.trim(); - if ( - path.parent.type === 'CallExpression' && - t.isIdentifier(path.parent.callee) && - path.parent.callee.name === 't' - ) { - return; - } + const tCall = t.callExpression(t.identifier('t'), [t.stringLiteral(value)]); - if ( - koreanKeys.has(value) && - path.parent.type !== 'ImportDeclaration' && - path.parent.type !== 'ExportNamedDeclaration' - ) { - if (path.parent.type === 'JSXAttribute') { - const tCall = t.callExpression(t.identifier('t'), [ - t.stringLiteral(value), - ]); - path.replaceWith(t.jsxExpressionContainer(tCall)); - } else { - const tCall = t.callExpression(t.identifier('t'), [ - t.stringLiteral(value), - ]); - path.replaceWith(tCall); - } + if (path.isJSXText()) { + path.replaceWith(t.jsxExpressionContainer(tCall)); + } else if (path.isStringLiteral()) { + if (path.parent.type === 'JSXAttribute') { + path.replaceWith(t.jsxExpressionContainer(tCall)); + } else { + path.replaceWith(tCall); } - }, + } }); return koreanKeys; From 21ee43c83142b2826ea2c1c6377ac7710e060f0e Mon Sep 17 00:00:00 2001 From: useon Date: Sat, 22 Nov 2025 03:11:19 +0900 Subject: [PATCH 14/16] =?UTF-8?q?refactor:=20=EB=B3=B5=EC=9E=A1=ED=95=9C?= =?UTF-8?q?=20=ED=99=95=EC=9E=A5=EC=9E=90=20=EC=B2=98=EB=A6=AC=EB=A5=BC=20?= =?UTF-8?q?=EC=9C=84=ED=95=9C=20=EB=9D=BC=EC=9D=B4=EB=B8=8C=EB=9F=AC?= =?UTF-8?q?=EB=A6=AC=20=EC=82=AC=EC=9A=A9=EC=9C=BC=EB=A1=9C=20=EB=8D=94?= =?UTF-8?q?=EC=9D=B4=EC=83=81=20=EC=82=AC=EC=9A=A9=ED=95=98=EC=A7=80=20?= =?UTF-8?q?=EC=95=8A=EB=8A=94=20=ED=99=95=EC=9E=A5=EC=9E=90=20=EC=B0=BE?= =?UTF-8?q?=EB=8A=94=20=ED=95=A8=EC=88=98=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/utils/fileUtils.ts | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/scripts/utils/fileUtils.ts b/scripts/utils/fileUtils.ts index 0ef8933c..2f8c0be8 100644 --- a/scripts/utils/fileUtils.ts +++ b/scripts/utils/fileUtils.ts @@ -53,36 +53,3 @@ export async function writeJSON( await writeFile(filePath, JSON.stringify(data, null, 2)); console.log(`[writeJSON] JSON 데이터 저장 완료: ${filePath}`); } - -/** 특정 확장자 파일들을 재귀적으로 찾기 */ -export async function getAllFiles( - dir: string, - ext: string, - fileList: string[] = [], -): Promise { - try { - // 비동기적으로 디렉토리 내용 읽기 - const entries = await fsp.readdir(dir, { withFileTypes: true }); - - // 모든 재귀 호출을 Promise.all로 병렬 처리 - const promises = entries.map(async (entry) => { - const fullPath = path.join(dir, entry.name); - - if (entry.isDirectory()) { - // 디렉토리인 경우, 비동기 재귀 호출을 하고 결과 병합 - const nestedFiles = await getAllFiles(fullPath, ext); - fileList.push(...nestedFiles); - } else if (entry.isFile() && entry.name.endsWith(ext)) { - // 파일인 경우, 리스트에 추가 - fileList.push(fullPath); - } - }); - - // 모든 비동기 작업(하위 디렉토리 순회)이 완료될 때까지 기다림 - await Promise.all(promises); - } catch (err) { - console.error(`에러 발생 디렉토리 ${dir}:`, err); - } - - return fileList; -} From 8ff5e40deee13c03db7c7d647f09d5eae19070fe Mon Sep 17 00:00:00 2001 From: useon Date: Mon, 1 Dec 2025 21:18:41 +0900 Subject: [PATCH 15/16] =?UTF-8?q?fix:=20ts-node=20=EC=8B=A4=ED=96=89=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=ED=95=B4=EA=B2=B0=20=EB=B0=8F=20tsx=20?= =?UTF-8?q?=EA=B8=B0=EB=B0=98=EC=9C=BC=EB=A1=9C=20=EC=8A=A4=ED=81=AC?= =?UTF-8?q?=EB=A6=BD=ED=8A=B8=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 686 +++++++++++++++++++++++++++++++++++----------- package.json | 4 +- 2 files changed, 530 insertions(+), 160 deletions(-) diff --git a/package-lock.json b/package-lock.json index 24de3346..7e082515 100644 --- a/package-lock.json +++ b/package-lock.json @@ -78,7 +78,7 @@ "stylelint-config-recommended": "^14.0.1", "stylelint-config-tailwindcss": "^0.0.7", "tailwindcss": "^3.4.16", - "ts-node": "^10.9.2", + "tsx": "^4.21.0", "typescript": "^5.7.2", "typescript-eslint": "^8.15.0", "vite": "^6.0.1", @@ -498,30 +498,6 @@ "storybook": "^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, "node_modules/@csstools/css-parser-algorithms": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", @@ -957,6 +933,23 @@ "node": ">=18" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.0.tgz", + "integrity": "sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { "version": "0.25.0", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz", @@ -2945,34 +2938,6 @@ "@testing-library/dom": ">=7.21.4" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/aria-query": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", @@ -3656,19 +3621,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/agent-base": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.2.tgz", @@ -4596,13 +4548,6 @@ } } }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, - "license": "MIT" - }, "node_modules/cross-fetch": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", @@ -4876,16 +4821,6 @@ "dev": true, "license": "Apache-2.0" }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -6089,6 +6024,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz", + "integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/glob": { "version": "11.0.3", "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz", @@ -7611,13 +7559,6 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" - }, "node_modules/map-or-similar": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/map-or-similar/-/map-or-similar-1.5.0.tgz", @@ -9159,6 +9100,16 @@ "node": ">=4" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -10662,57 +10613,6 @@ "dev": true, "license": "Apache-2.0" }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node/node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, - "license": "MIT" - }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -10745,6 +10645,493 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.0.tgz", + "integrity": "sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.0.tgz", + "integrity": "sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.0.tgz", + "integrity": "sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.0.tgz", + "integrity": "sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.0.tgz", + "integrity": "sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.0.tgz", + "integrity": "sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.0.tgz", + "integrity": "sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.0.tgz", + "integrity": "sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.0.tgz", + "integrity": "sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.0.tgz", + "integrity": "sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.0.tgz", + "integrity": "sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.0.tgz", + "integrity": "sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.0.tgz", + "integrity": "sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.0.tgz", + "integrity": "sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.0.tgz", + "integrity": "sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.0.tgz", + "integrity": "sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.0.tgz", + "integrity": "sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.0.tgz", + "integrity": "sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.0.tgz", + "integrity": "sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.0.tgz", + "integrity": "sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.0.tgz", + "integrity": "sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.0.tgz", + "integrity": "sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.0.tgz", + "integrity": "sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.0.tgz", + "integrity": "sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.0.tgz", + "integrity": "sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.0.tgz", + "integrity": "sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.0", + "@esbuild/android-arm": "0.27.0", + "@esbuild/android-arm64": "0.27.0", + "@esbuild/android-x64": "0.27.0", + "@esbuild/darwin-arm64": "0.27.0", + "@esbuild/darwin-x64": "0.27.0", + "@esbuild/freebsd-arm64": "0.27.0", + "@esbuild/freebsd-x64": "0.27.0", + "@esbuild/linux-arm": "0.27.0", + "@esbuild/linux-arm64": "0.27.0", + "@esbuild/linux-ia32": "0.27.0", + "@esbuild/linux-loong64": "0.27.0", + "@esbuild/linux-mips64el": "0.27.0", + "@esbuild/linux-ppc64": "0.27.0", + "@esbuild/linux-riscv64": "0.27.0", + "@esbuild/linux-s390x": "0.27.0", + "@esbuild/linux-x64": "0.27.0", + "@esbuild/netbsd-arm64": "0.27.0", + "@esbuild/netbsd-x64": "0.27.0", + "@esbuild/openbsd-arm64": "0.27.0", + "@esbuild/openbsd-x64": "0.27.0", + "@esbuild/openharmony-arm64": "0.27.0", + "@esbuild/sunos-x64": "0.27.0", + "@esbuild/win32-arm64": "0.27.0", + "@esbuild/win32-ia32": "0.27.0", + "@esbuild/win32-x64": "0.27.0" + } + }, "node_modules/tween-functions": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/tween-functions/-/tween-functions-1.2.0.tgz", @@ -11031,13 +11418,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, - "license": "MIT" - }, "node_modules/vite": { "version": "6.3.5", "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", @@ -12744,16 +13124,6 @@ "node": ">=8" } }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index a1f3403d..417f1bf5 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "build-storybook": "storybook build", "test": "vitest", "chromatic": "npx chromatic --project-token=chpt_a6dc39eba6488b2", - "i18n:transform": "ts-node scripts/i18nTransform.ts" + "i18n:transform": "tsx scripts/i18nTransform.ts" }, "dependencies": { "@tanstack/eslint-plugin-query": "^5.62.9", @@ -89,7 +89,7 @@ "stylelint-config-recommended": "^14.0.1", "stylelint-config-tailwindcss": "^0.0.7", "tailwindcss": "^3.4.16", - "ts-node": "^10.9.2", + "tsx": "^4.21.0", "typescript": "^5.7.2", "typescript-eslint": "^8.15.0", "vite": "^6.0.1", From 99144022e997cb84d7ce54d870da7ef226f274f2 Mon Sep 17 00:00:00 2001 From: useon Date: Mon, 8 Dec 2025 15:44:47 +0900 Subject: [PATCH 16/16] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=A3=BC=EC=84=9D=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/utils/fileUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/utils/fileUtils.ts b/scripts/utils/fileUtils.ts index 2f8c0be8..6782f748 100644 --- a/scripts/utils/fileUtils.ts +++ b/scripts/utils/fileUtils.ts @@ -16,7 +16,7 @@ export async function readJSON(filePath: string): Promise { export async function ensureFile(filePath: string): Promise { const dir = path.dirname(filePath); - // 1. 디렉토리 구조 보장 (writeFile에서 mkdir을 처리하므로, 여기서는 fsp.access를 사용) + // 1. 디렉토리 구조 보장 try { // 디렉토리가 존재하는지 확인 await fsp.access(dir);